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 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and/or associated documentation files (the
11 * "Materials"), to deal in the Materials without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Materials, and to
14 * permit persons to whom the Materials are furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice(s) and this permission notice shall be included
18 * in all copies or substantial portions of the Materials.
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
30 * \brief Shader loop tests.
31 *//*--------------------------------------------------------------------*/
33 #include "vktShaderRenderLoopTests.hpp"
35 #include "vktShaderRender.hpp"
36 #include "tcuStringTemplate.hpp"
37 #include "gluShaderUtil.hpp"
38 #include "deStringUtil.hpp"
49 static const char* getIntUniformName (int number)
53 case 0: return "ui_zero";
54 case 1: return "ui_one";
55 case 2: return "ui_two";
56 case 3: return "ui_three";
57 case 4: return "ui_four";
58 case 5: return "ui_five";
59 case 6: return "ui_six";
60 case 7: return "ui_seven";
61 case 8: return "ui_eight";
62 case 101: return "ui_oneHundredOne";
69 static BaseUniformType getIntUniformType(int number)
73 case 1: return UI_ONE;
74 case 2: return UI_TWO;
75 case 3: return UI_THREE;
76 case 4: return UI_FOUR;
77 case 5: return UI_FIVE;
78 case 6: return UI_SIX;
79 case 7: return UI_SEVEN;
80 case 8: return UI_EIGHT;
87 static const char* getFloatFractionUniformName (int number)
91 case 1: return "uf_one";
92 case 2: return "uf_half";
93 case 3: return "uf_third";
94 case 4: return "uf_fourth";
95 case 5: return "uf_fifth";
96 case 6: return "uf_sixth";
97 case 7: return "uf_seventh";
98 case 8: return "uf_eight";
105 static BaseUniformType getFloatFractionUniformType(int number)
109 case 1: return UF_ONE;
110 case 2: return UF_HALF;
111 case 3: return UF_THIRD;
112 case 4: return UF_FOURTH;
113 case 5: return UF_FIFTH;
114 case 6: return UF_SIXTH;
115 case 7: return UF_SEVENTH;
116 case 8: return UF_EIGHTH;
131 static const char* getLoopTypeName (LoopType loopType)
133 static const char* s_names[] =
140 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
141 DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
142 return s_names[(int)loopType];
147 LOOPCOUNT_CONSTANT = 0,
154 // Repeated with for, while, do-while. Examples given as 'for' loops.
155 // Repeated for const, uniform, dynamic loops.
158 LOOPCASE_EMPTY_BODY = 0, // for (...) { }
159 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
160 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
161 LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
162 LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
163 LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
164 LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
165 LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
166 LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
167 LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
168 LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
169 LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
170 LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
171 LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; $
172 LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
173 LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
174 LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
175 LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
176 LOOPCASE_MIXED_BREAK_CONTINUE,
177 LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx$
178 LOOPCASE_101_ITERATIONS, // loop for 101 iterations
179 LOOPCASE_SEQUENCE, // two loops in sequence
180 LOOPCASE_NESTED, // two nested loops
181 LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a th$
182 LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
183 LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
185 //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
190 static const char* getLoopCaseName (LoopCase loopCase)
192 static const char* s_names[] =
195 "infinite_with_unconditional_break_first",
196 "infinite_with_unconditional_break_last",
197 "infinite_with_conditional_break",
199 "compound_statement",
200 "sequence_statement",
203 "select_iteration_count",
204 "conditional_continue",
205 "unconditional_continue",
209 "unconditional_break",
212 "mixed_break_continue",
218 "nested_tricky_dataflow_1",
219 "nested_tricky_dataflow_2"
220 //"multi_declaration",
223 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
224 DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
225 return s_names[(int)loopCase];
228 static const char* getLoopCountTypeName (LoopCountType countType)
230 static const char* s_names[] =
237 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
238 DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
239 return s_names[(int)countType];
242 static void evalLoop0Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
243 static void evalLoop1Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(1,2,3); }
244 static void evalLoop2Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(2,3,0); }
245 static void evalLoop3Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,0,1); }
247 static ShaderEvalFunc getLoopEvalFunc (int numIters)
249 switch (numIters % 4)
251 case 0: return evalLoop0Iters;
252 case 1: return evalLoop1Iters;
253 case 2: return evalLoop2Iters;
254 case 3: return evalLoop3Iters;
257 DE_FATAL("Invalid loop iteration count.");
263 class ShaderLoopCase : public ShaderRenderCase
266 ShaderLoopCase (tcu::TestContext& testCtx,
267 const std::string& name,
268 const std::string& description,
270 ShaderEvalFunc evalFunc,
271 UniformSetup* uniformSetup,
272 const std::string& vertexShaderSource,
273 const std::string& fragmentShaderSource)
274 : ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, uniformSetup, DE_NULL)
276 m_vertShaderSource = vertexShaderSource;
277 m_fragShaderSource = fragmentShaderSource;
281 // Uniform setup tools
283 class LoopUniformSetup : public UniformSetup
286 LoopUniformSetup (std::vector<BaseUniformType>& types)
287 : m_uniformInformations(types)
290 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
293 std::vector<BaseUniformType> m_uniformInformations;
296 void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
298 for (size_t i = 0; i < m_uniformInformations.size(); i++)
300 instance.useUniform((deUint32)i, m_uniformInformations[i]);
306 static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext& testCtx,
307 const std::string& caseName,
308 const std::string& description,
311 LoopCountType loopCountType,
312 glu::Precision loopCountPrecision,
313 glu::DataType loopCountDataType)
315 std::ostringstream vtx;
316 std::ostringstream frag;
317 std::ostringstream& op = isVertexCase ? vtx : frag;
319 vtx << "#version 310 es\n";
320 frag << "#version 310 es\n";
322 vtx << "layout(location=0) in highp vec4 a_position;\n";
323 vtx << "layout(location=1) in highp vec4 a_coords;\n";
324 frag << "layout(location=0) out mediump vec4 o_color;\n";
326 if (loopCountType == LOOPCOUNT_DYNAMIC)
327 vtx << "layout(location=3) in mediump float a_one;\n";
331 vtx << "layout(location=0) out mediump vec3 v_color;\n";
332 frag << "layout(location=0) in mediump vec3 v_color;\n";
336 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
337 frag << "layout(location=0) in mediump vec4 v_coords;\n";
339 if (loopCountType == LOOPCOUNT_DYNAMIC)
341 vtx << "layout(location=1) out mediump float v_one;\n";
342 frag << "layout(location=1) in mediump float v_one;\n";
346 const int numLoopIters = 3;
347 const bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
348 deUint32 locationCounter = 0;
349 std::vector<BaseUniformType> uniformInformations;
353 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
355 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
356 op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
358 uniformInformations.push_back(getIntUniformType(numLoopIters));
364 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
365 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
366 op << " ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
368 uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
372 if (numLoopIters != 1){
373 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
374 op << " ${COUNTER_PRECISION} float uf_one;\n";
376 uniformInformations.push_back(UF_ONE);
382 vtx << "void main()\n";
384 vtx << " gl_Position = a_position;\n";
387 frag << "void main()\n";
391 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
393 frag << " ${PRECISION} vec4 coords = v_coords;\n";
396 if (loopCountType == LOOPCOUNT_DYNAMIC)
401 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
403 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
408 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
410 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
415 op << " ${PRECISION} vec4 res = coords;\n";
417 // Loop iteration count.
418 std::string iterMaxStr;
422 if (loopCountType == LOOPCOUNT_CONSTANT)
423 iterMaxStr = de::toString(numLoopIters);
424 else if (loopCountType == LOOPCOUNT_UNIFORM)
425 iterMaxStr = getIntUniformName(numLoopIters);
426 else if (loopCountType == LOOPCOUNT_DYNAMIC)
427 iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
433 if (loopCountType == LOOPCOUNT_CONSTANT)
435 else if (loopCountType == LOOPCOUNT_UNIFORM)
436 iterMaxStr = "uf_one";
437 else if (loopCountType == LOOPCOUNT_DYNAMIC)
438 iterMaxStr = "uf_one*one";
444 std::string initValue = isIntCounter ? "0" : "0.05";
445 std::string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
446 std::string loopCmpStr = ("ndx < " + iterMaxStr);
447 std::string incrementStr;
449 incrementStr = "ndx++";
452 if (loopCountType == LOOPCOUNT_CONSTANT)
453 incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
454 else if (loopCountType == LOOPCOUNT_UNIFORM)
455 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
456 else if (loopCountType == LOOPCOUNT_DYNAMIC)
457 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
463 std::string loopBody;
465 loopBody = " res = res.yzwx;\n";
467 if (loopType == LOOPTYPE_FOR)
469 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
474 else if (loopType == LOOPTYPE_WHILE)
476 op << "\t" << loopCountDeclStr + ";\n";
477 op << " while (" + loopCmpStr + ")\n";
480 op << "\t\t" + incrementStr + ";\n";
483 else if (loopType == LOOPTYPE_DO_WHILE)
485 op << "\t" << loopCountDeclStr + ";\n";
489 op << "\t\t" + incrementStr + ";\n";
490 op << " } while (" + loopCmpStr + ");\n";
497 vtx << " v_color = res.rgb;\n";
498 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
502 vtx << " v_coords = a_coords;\n";
503 frag << " o_color = vec4(res.rgb, 1.0);\n";
505 if (loopCountType == LOOPCOUNT_DYNAMIC)
506 vtx << " v_one = a_one;\n";
512 // Fill in shader templates.
513 std::map<std::string, std::string> params;
514 params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
515 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
516 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
518 tcu::StringTemplate vertTemplate(vtx.str());
519 tcu::StringTemplate fragTemplate(frag.str());
520 std::string vertexShaderSource = vertTemplate.specialize(params);
521 std::string fragmentShaderSource = fragTemplate.specialize(params);
524 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
525 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
526 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
529 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext& testCtx,
530 const std::string& caseName,
531 const std::string& description,
535 LoopCountType loopCountType)
537 std::ostringstream vtx;
538 std::ostringstream frag;
539 std::ostringstream& op = isVertexCase ? vtx : frag;
541 std::vector<BaseUniformType> uniformInformations;
542 deUint32 locationCounter = 0;
544 vtx << "#version 310 es\n";
545 frag << "#version 310 es\n";
547 vtx << "layout(location=0) in highp vec4 a_position;\n";
548 vtx << "layout(location=1) in highp vec4 a_coords;\n";
549 frag << "layout(location=0) out mediump vec4 o_color;\n";
551 if (loopCountType == LOOPCOUNT_DYNAMIC)
552 vtx << "layout(location=3) in mediump float a_one;\n";
556 vtx << "layout(location=0) out mediump vec3 v_color;\n";
557 frag << "layout(location=0) in mediump vec3 v_color;\n";
561 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
562 frag << "layout(location=0) in mediump vec4 v_coords;\n";
564 if (loopCountType == LOOPCOUNT_DYNAMIC)
566 vtx << "layout(location=1) out mediump float v_one;\n";
567 frag << "layout(location=1) in mediump float v_one;\n";
571 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
572 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
573 op << " bool ub_true;\n";
575 uniformInformations.push_back(UB_TRUE);
582 BaseUniformType type;
585 { "ui_zero", UI_ZERO },
586 { "ui_one", UI_ONE },
587 { "ui_two", UI_TWO },
588 { "ui_three", UI_THREE },
589 { "ui_four", UI_FOUR },
590 { "ui_five", UI_FIVE },
591 { "ui_six", UI_SIX },
594 for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
596 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
597 op << " ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
599 uniformInformations.push_back(uniforms[i].type);
603 if (loopCase == LOOPCASE_101_ITERATIONS) {
605 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
606 op << " ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
608 uniformInformations.push_back(UI_ONEHUNDREDONE);
612 int iterCount = 3; // value to use in loop
613 int numIters = 3; // actual number of iterations
616 vtx << "void main()\n";
618 vtx << " gl_Position = a_position;\n";
621 frag << "void main()\n";
624 if (loopCountType == LOOPCOUNT_DYNAMIC)
627 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
629 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
633 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
635 frag << " ${PRECISION} vec4 coords = v_coords;\n";
638 op << " ${PRECISION} vec4 res = coords;\n";
640 // Handle all loop types.
641 std::string counterPrecisionStr = "mediump";
642 std::string forLoopStr;
643 std::string whileLoopStr;
644 std::string doWhileLoopPreStr;
645 std::string doWhileLoopPostStr;
647 if (loopType == LOOPTYPE_FOR)
651 case LOOPCASE_EMPTY_BODY:
653 op << " ${FOR_LOOP} {}\n";
656 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
658 op << " for (;;) { break; res = res.yzwx; }\n";
661 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
663 op << " for (;;) { res = res.yzwx; break; }\n";
666 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
668 op << " ${COUNTER_PRECISION} int i = 0;\n";
669 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
672 case LOOPCASE_SINGLE_STATEMENT:
673 op << " ${FOR_LOOP} res = res.yzwx;\n";
676 case LOOPCASE_COMPOUND_STATEMENT:
678 numIters = 2 * iterCount;
679 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
682 case LOOPCASE_SEQUENCE_STATEMENT:
684 numIters = 2 * iterCount;
685 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
688 case LOOPCASE_NO_ITERATIONS:
691 op << " ${FOR_LOOP} res = res.yzwx;\n";
694 case LOOPCASE_SINGLE_ITERATION:
697 op << " ${FOR_LOOP} res = res.yzwx;\n";
700 case LOOPCASE_SELECT_ITERATION_COUNT:
701 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
704 case LOOPCASE_CONDITIONAL_CONTINUE:
705 numIters = iterCount - 1;
706 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
709 case LOOPCASE_UNCONDITIONAL_CONTINUE:
710 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
713 case LOOPCASE_ONLY_CONTINUE:
715 op << " ${FOR_LOOP} { continue; }\n";
718 case LOOPCASE_DOUBLE_CONTINUE:
719 numIters = iterCount - 1;
720 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
723 case LOOPCASE_CONDITIONAL_BREAK:
725 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
728 case LOOPCASE_UNCONDITIONAL_BREAK:
730 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
733 case LOOPCASE_PRE_INCREMENT:
734 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
737 case LOOPCASE_POST_INCREMENT:
738 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
741 case LOOPCASE_MIXED_BREAK_CONTINUE:
744 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
747 case LOOPCASE_VECTOR_COUNTER:
748 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx; }\n";
751 case LOOPCASE_101_ITERATIONS:
752 numIters = iterCount = 101;
753 op << " ${FOR_LOOP} res = res.yzwx;\n";
756 case LOOPCASE_SEQUENCE:
759 op << " ${COUNTER_PRECISION} int i;\n";
760 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
761 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
764 case LOOPCASE_NESTED:
765 numIters = 2 * iterCount;
766 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
768 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
769 op << " res = res.yzwx;\n";
773 case LOOPCASE_NESTED_SEQUENCE:
774 numIters = 3 * iterCount;
775 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
777 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
778 op << " res = res.yzwx;\n";
779 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
780 op << " res = res.yzwx;\n";
784 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
786 op << " ${FOR_LOOP}\n";
788 op << " res = coords; // ignore outer loop effect \n";
789 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
790 op << " res = res.yzwx;\n";
794 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
795 numIters = iterCount;
796 op << " ${FOR_LOOP}\n";
798 op << " res = coords.wxyz;\n";
799 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
800 op << " res = res.yzwx;\n";
801 op << " coords = res;\n";
809 if (loopCountType == LOOPCOUNT_CONSTANT)
810 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
811 else if (loopCountType == LOOPCOUNT_UNIFORM)
812 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
813 else if (loopCountType == LOOPCOUNT_DYNAMIC)
814 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
818 else if (loopType == LOOPTYPE_WHILE)
822 case LOOPCASE_EMPTY_BODY:
824 op << " ${WHILE_LOOP} {}\n";
827 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
829 op << " while (true) { break; res = res.yzwx; }\n";
832 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
834 op << " while (true) { res = res.yzwx; break; }\n";
837 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
839 op << " ${COUNTER_PRECISION} int i = 0;\n";
840 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
843 case LOOPCASE_SINGLE_STATEMENT:
844 op << " ${WHILE_LOOP} res = res.yzwx;\n";
847 case LOOPCASE_COMPOUND_STATEMENT:
849 numIters = 2 * iterCount;
850 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
853 case LOOPCASE_SEQUENCE_STATEMENT:
855 numIters = 2 * iterCount;
856 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
859 case LOOPCASE_NO_ITERATIONS:
862 op << " ${WHILE_LOOP} res = res.yzwx;\n";
865 case LOOPCASE_SINGLE_ITERATION:
868 op << " ${WHILE_LOOP} res = res.yzwx;\n";
871 case LOOPCASE_SELECT_ITERATION_COUNT:
872 op << " ${COUNTER_PRECISION} int i = 0;\n";
873 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
876 case LOOPCASE_CONDITIONAL_CONTINUE:
877 numIters = iterCount - 1;
878 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
881 case LOOPCASE_UNCONDITIONAL_CONTINUE:
882 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
885 case LOOPCASE_ONLY_CONTINUE:
887 op << " ${WHILE_LOOP} { continue; }\n";
890 case LOOPCASE_DOUBLE_CONTINUE:
891 numIters = iterCount - 1;
892 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
895 case LOOPCASE_CONDITIONAL_BREAK:
897 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
900 case LOOPCASE_UNCONDITIONAL_BREAK:
902 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
905 case LOOPCASE_PRE_INCREMENT:
906 numIters = iterCount - 1;
907 op << " ${COUNTER_PRECISION} int i = 0;\n";
908 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
911 case LOOPCASE_POST_INCREMENT:
912 op << " ${COUNTER_PRECISION} int i = 0;\n";
913 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
916 case LOOPCASE_MIXED_BREAK_CONTINUE:
919 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
922 case LOOPCASE_VECTOR_COUNTER:
923 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
924 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
927 case LOOPCASE_101_ITERATIONS:
928 numIters = iterCount = 101;
929 op << " ${WHILE_LOOP} res = res.yzwx;\n";
932 case LOOPCASE_SEQUENCE:
934 numIters = iterCount - 1;
935 op << " ${COUNTER_PRECISION} int i = 0;\n";
936 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
937 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
940 case LOOPCASE_NESTED:
941 numIters = 2 * iterCount;
942 op << " ${COUNTER_PRECISION} int i = 0;\n";
943 op << " while (i++ < ${TWO})\n";
945 op << " ${COUNTER_PRECISION} int j = 0;\n";
946 op << " while (j++ < ${ITER_COUNT})\n";
947 op << " res = res.yzwx;\n";
951 case LOOPCASE_NESTED_SEQUENCE:
952 numIters = 2 * iterCount;
953 op << " ${COUNTER_PRECISION} int i = 0;\n";
954 op << " while (i++ < ${ITER_COUNT})\n";
956 op << " ${COUNTER_PRECISION} int j = 0;\n";
957 op << " while (j++ < ${ONE})\n";
958 op << " res = res.yzwx;\n";
959 op << " while (j++ < ${THREE})\n"; // \note skips one iteration
960 op << " res = res.yzwx;\n";
964 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
966 op << " ${WHILE_LOOP}\n";
968 op << " res = coords; // ignore outer loop effect \n";
969 op << " ${COUNTER_PRECISION} int j = 0;\n";
970 op << " while (j++ < ${TWO})\n";
971 op << " res = res.yzwx;\n";
975 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
976 numIters = iterCount;
977 op << " ${WHILE_LOOP}\n";
979 op << " res = coords.wxyz;\n";
980 op << " ${COUNTER_PRECISION} int j = 0;\n";
981 op << " while (j++ < ${TWO})\n";
982 op << " res = res.yzwx;\n";
983 op << " coords = res;\n";
991 if (loopCountType == LOOPCOUNT_CONSTANT)
992 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")";
993 else if (loopCountType == LOOPCOUNT_UNIFORM)
994 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + getIntUniformName(iterCount) + ")";
995 else if (loopCountType == LOOPCOUNT_DYNAMIC)
996 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" + getIntUniformName(iterCount) + ")";
1002 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
1006 case LOOPCASE_EMPTY_BODY:
1008 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1011 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1013 op << " do { break; res = res.yzwx; } while (true);\n";
1016 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1018 op << " do { res = res.yzwx; break; } while (true);\n";
1021 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1023 op << " ${COUNTER_PRECISION} int i = 0;\n";
1024 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
1027 case LOOPCASE_SINGLE_STATEMENT:
1028 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1031 case LOOPCASE_COMPOUND_STATEMENT:
1033 numIters = 2 * iterCount;
1034 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
1037 case LOOPCASE_SEQUENCE_STATEMENT:
1039 numIters = 2 * iterCount;
1040 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
1043 case LOOPCASE_NO_ITERATIONS:
1047 case LOOPCASE_SINGLE_ITERATION:
1050 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1053 case LOOPCASE_SELECT_ITERATION_COUNT:
1054 op << " ${COUNTER_PRECISION} int i = 0;\n";
1055 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1058 case LOOPCASE_CONDITIONAL_CONTINUE:
1059 numIters = iterCount - 1;
1060 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
1063 case LOOPCASE_UNCONDITIONAL_CONTINUE:
1064 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1067 case LOOPCASE_ONLY_CONTINUE:
1069 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1072 case LOOPCASE_DOUBLE_CONTINUE:
1073 numIters = iterCount - 1;
1074 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1077 case LOOPCASE_CONDITIONAL_BREAK:
1079 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1082 case LOOPCASE_UNCONDITIONAL_BREAK:
1084 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
1087 case LOOPCASE_PRE_INCREMENT:
1088 op << " ${COUNTER_PRECISION} int i = 0;\n";
1089 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1092 case LOOPCASE_POST_INCREMENT:
1093 numIters = iterCount + 1;
1094 op << " ${COUNTER_PRECISION} int i = 0;\n";
1095 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
1098 case LOOPCASE_MIXED_BREAK_CONTINUE:
1101 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } ${DO_WHILE_POST}\n";
1104 case LOOPCASE_VECTOR_COUNTER:
1105 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1106 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1109 case LOOPCASE_101_ITERATIONS:
1110 numIters = iterCount = 101;
1111 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1114 case LOOPCASE_SEQUENCE:
1117 op << " ${COUNTER_PRECISION} int i = 0;\n";
1118 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
1119 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1122 case LOOPCASE_NESTED:
1123 numIters = 2 * iterCount;
1124 op << " ${COUNTER_PRECISION} int i = 0;\n";
1127 op << " ${COUNTER_PRECISION} int j = 0;\n";
1129 op << " res = res.yzwx;\n";
1130 op << " while (++j < ${ITER_COUNT});\n";
1131 op << " } while (++i < ${TWO});\n";
1134 case LOOPCASE_NESTED_SEQUENCE:
1135 numIters = 3 * iterCount;
1136 op << " ${COUNTER_PRECISION} int i = 0;\n";
1139 op << " ${COUNTER_PRECISION} int j = 0;\n";
1141 op << " res = res.yzwx;\n";
1142 op << " while (++j < ${TWO});\n";
1144 op << " res = res.yzwx;\n";
1145 op << " while (++j < ${THREE});\n";
1146 op << " } while (++i < ${ITER_COUNT});\n";
1149 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1151 op << " ${DO_WHILE_PRE}\n";
1153 op << " res = coords; // ignore outer loop effect \n";
1154 op << " ${COUNTER_PRECISION} int j = 0;\n";
1156 op << " res = res.yzwx;\n";
1157 op << " while (++j < ${TWO});\n";
1158 op << " } ${DO_WHILE_POST}\n";
1161 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1162 numIters = iterCount;
1163 op << " ${DO_WHILE_PRE}\n";
1165 op << " res = coords.wxyz;\n";
1166 op << " ${COUNTER_PRECISION} int j = 0;\n";
1167 op << " while (j++ < ${TWO})\n";
1168 op << " res = res.yzwx;\n";
1169 op << " coords = res;\n";
1170 op << " } ${DO_WHILE_POST}\n";
1177 doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1178 if (loopCountType == LOOPCOUNT_CONSTANT)
1179 doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1180 else if (loopCountType == LOOPCOUNT_UNIFORM)
1181 doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1182 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1183 doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1191 vtx << " v_color = res.rgb;\n";
1192 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
1196 vtx << " v_coords = a_coords;\n";
1197 frag << " o_color = vec4(res.rgb, 1.0);\n";
1199 if (loopCountType == LOOPCOUNT_DYNAMIC)
1200 vtx << " v_one = a_one;\n";
1209 std::string threeStr;
1210 std::string iterCountStr;
1212 if (loopCountType == LOOPCOUNT_CONSTANT)
1217 iterCountStr = de::toString(iterCount);
1219 else if (loopCountType == LOOPCOUNT_UNIFORM)
1223 threeStr = "ui_three";
1224 iterCountStr = getIntUniformName(iterCount);
1226 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1228 oneStr = "one*ui_one";
1229 twoStr = "one*ui_two";
1230 threeStr = "one*ui_three";
1231 iterCountStr = std::string("one*") + getIntUniformName(iterCount);
1233 else DE_ASSERT(false);
1235 // Fill in shader templates.
1236 std::map<std::string, std::string> params;
1237 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1238 params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1239 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1240 params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1241 params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1242 params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1243 params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1244 params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1245 params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1246 params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1248 tcu::StringTemplate vertTemplate(vtx.str());
1249 tcu::StringTemplate fragTemplate(frag.str());
1250 std::string vertexShaderSource = vertTemplate.specialize(params);
1251 std::string fragmentShaderSource = fragTemplate.specialize(params);
1254 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1255 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1256 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1259 class ShaderLoopTests : public tcu::TestCaseGroup
1262 ShaderLoopTests (tcu::TestContext& testCtx);
1263 virtual ~ShaderLoopTests (void);
1265 virtual void init (void);
1268 ShaderLoopTests (const ShaderLoopTests&); // not allowed!
1269 ShaderLoopTests& operator= (const ShaderLoopTests&); // not allowed!
1272 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1273 : TestCaseGroup(testCtx, "loops", "Loop Tests")
1277 ShaderLoopTests::~ShaderLoopTests (void)
1281 void ShaderLoopTests::init (void)
1285 static const glu::ShaderType s_shaderTypes[] =
1287 glu::SHADERTYPE_VERTEX,
1288 glu::SHADERTYPE_FRAGMENT
1291 static const glu::DataType s_countDataType[] =
1297 TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
1298 TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
1299 addChild(genericGroup);
1300 addChild(specialGroup);
1302 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1304 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1306 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1308 const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1310 std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1311 std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1312 TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1313 TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1314 genericGroup->addChild(genericSubGroup);
1315 specialGroup->addChild(specialSubGroup);
1319 for (int precision = glu::PRECISION_MEDIUMP; precision < glu::PRECISION_LAST; precision++)
1321 const char* precisionName = getPrecisionName((glu::Precision)precision);
1323 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1325 glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1326 const char* dataTypeName = getDataTypeName(loopDataType);
1328 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1330 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1331 const char* shaderTypeName = getShaderTypeName(shaderType);
1332 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1334 std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1335 std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
1336 de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1337 genericSubGroup->addChild(testCase.release());
1344 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1346 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1348 // no-iterations not possible with do-while.
1349 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1352 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1354 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1355 const char* shaderTypeName = getShaderTypeName(shaderType);
1356 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1358 std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1359 std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
1360 de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1361 specialSubGroup->addChild(testCase.release());
1370 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1372 return new ShaderLoopTests(testCtx);