1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and/or associated documentation files (the
10 * "Materials"), to deal in the Materials without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Materials, and to
13 * permit persons to whom the Materials are furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice(s) and this permission notice shall be included
17 * in all copies or substantial portions of the Materials.
19 * The Materials are Confidential Information as defined by the
20 * Khronos Membership Agreement until designated non-confidential by Khronos,
21 * at which point this condition clause shall be removed.
23 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
33 * \brief Shader loop tests.
34 *//*--------------------------------------------------------------------*/
36 #include "vktShaderRenderLoopTests.hpp"
38 #include "vktShaderRender.hpp"
39 #include "tcuStringTemplate.hpp"
40 #include "gluShaderUtil.hpp"
41 #include "deStringUtil.hpp"
52 static const char* getIntUniformName (int number)
56 case 0: return "ui_zero";
57 case 1: return "ui_one";
58 case 2: return "ui_two";
59 case 3: return "ui_three";
60 case 4: return "ui_four";
61 case 5: return "ui_five";
62 case 6: return "ui_six";
63 case 7: return "ui_seven";
64 case 8: return "ui_eight";
65 case 101: return "ui_oneHundredOne";
72 static BaseUniformType getIntUniformType(int number)
76 case 1: return UI_ONE;
77 case 2: return UI_TWO;
78 case 3: return UI_THREE;
79 case 4: return UI_FOUR;
80 case 5: return UI_FIVE;
81 case 6: return UI_SIX;
82 case 7: return UI_SEVEN;
83 case 8: return UI_EIGHT;
90 static const char* getFloatFractionUniformName (int number)
94 case 1: return "uf_one";
95 case 2: return "uf_half";
96 case 3: return "uf_third";
97 case 4: return "uf_fourth";
98 case 5: return "uf_fifth";
99 case 6: return "uf_sixth";
100 case 7: return "uf_seventh";
101 case 8: return "uf_eight";
108 static BaseUniformType getFloatFractionUniformType(int number)
112 case 1: return UF_ONE;
113 case 2: return UF_HALF;
114 case 3: return UF_THIRD;
115 case 4: return UF_FOURTH;
116 case 5: return UF_FIFTH;
117 case 6: return UF_SIXTH;
118 case 7: return UF_SEVENTH;
119 case 8: return UF_EIGHTH;
134 static const char* getLoopTypeName (LoopType loopType)
136 static const char* s_names[] =
143 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
144 DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
145 return s_names[(int)loopType];
150 LOOPCOUNT_CONSTANT = 0,
157 // Repeated with for, while, do-while. Examples given as 'for' loops.
158 // Repeated for const, uniform, dynamic loops.
161 LOOPCASE_EMPTY_BODY = 0, // for (...) { }
162 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
163 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
164 LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
165 LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
166 LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
167 LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
168 LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
169 LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
170 LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
171 LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
172 LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
173 LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
174 LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; $
175 LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
176 LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
177 LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
178 LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
179 LOOPCASE_MIXED_BREAK_CONTINUE,
180 LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx$
181 LOOPCASE_101_ITERATIONS, // loop for 101 iterations
182 LOOPCASE_SEQUENCE, // two loops in sequence
183 LOOPCASE_NESTED, // two nested loops
184 LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a th$
185 LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
186 LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
188 //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
193 static const char* getLoopCaseName (LoopCase loopCase)
195 static const char* s_names[] =
198 "infinite_with_unconditional_break_first",
199 "infinite_with_unconditional_break_last",
200 "infinite_with_conditional_break",
202 "compound_statement",
203 "sequence_statement",
206 "select_iteration_count",
207 "conditional_continue",
208 "unconditional_continue",
212 "unconditional_break",
215 "mixed_break_continue",
221 "nested_tricky_dataflow_1",
222 "nested_tricky_dataflow_2"
223 //"multi_declaration",
226 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
227 DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
228 return s_names[(int)loopCase];
231 static const char* getLoopCountTypeName (LoopCountType countType)
233 static const char* s_names[] =
240 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
241 DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
242 return s_names[(int)countType];
245 static void evalLoop0Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
246 static void evalLoop1Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(1,2,3); }
247 static void evalLoop2Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(2,3,0); }
248 static void evalLoop3Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,0,1); }
250 static ShaderEvalFunc getLoopEvalFunc (int numIters)
252 switch (numIters % 4)
254 case 0: return evalLoop0Iters;
255 case 1: return evalLoop1Iters;
256 case 2: return evalLoop2Iters;
257 case 3: return evalLoop3Iters;
260 DE_FATAL("Invalid loop iteration count.");
266 class ShaderLoopCase : public ShaderRenderCase
269 ShaderLoopCase (tcu::TestContext& testCtx,
270 const std::string& name,
271 const std::string& description,
273 ShaderEvalFunc evalFunc,
274 UniformSetup* uniformSetup,
275 const std::string& vertexShaderSource,
276 const std::string& fragmentShaderSource)
277 : ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, uniformSetup, DE_NULL)
279 m_vertShaderSource = vertexShaderSource;
280 m_fragShaderSource = fragmentShaderSource;
284 // Uniform setup tools
286 class LoopUniformSetup : public UniformSetup
289 LoopUniformSetup (std::vector<BaseUniformType>& types)
290 : m_uniformInformations(types)
293 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
296 std::vector<BaseUniformType> m_uniformInformations;
299 void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
301 for (size_t i = 0; i < m_uniformInformations.size(); i++)
303 instance.useUniform((deUint32)i, m_uniformInformations[i]);
309 static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext& testCtx,
310 const std::string& caseName,
311 const std::string& description,
314 LoopCountType loopCountType,
315 glu::Precision loopCountPrecision,
316 glu::DataType loopCountDataType)
318 std::ostringstream vtx;
319 std::ostringstream frag;
320 std::ostringstream& op = isVertexCase ? vtx : frag;
322 vtx << "#version 140\n";
323 vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
324 vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
326 frag << "#version 140\n";
327 frag << "#extension GL_ARB_separate_shader_objects : enable\n";
328 frag << "#extension GL_ARB_shading_language_420pack : enable\n";
330 vtx << "layout(location=0) in highp vec4 a_position;\n";
331 vtx << "layout(location=1) in highp vec4 a_coords;\n";
332 frag << "layout(location=0) out mediump vec4 o_color;\n";
334 if (loopCountType == LOOPCOUNT_DYNAMIC)
335 vtx << "layout(location=3) in mediump float a_one;\n";
339 vtx << "layout(location=0) out mediump vec3 v_color;\n";
340 frag << "layout(location=0) in mediump vec3 v_color;\n";
344 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
345 frag << "layout(location=0) in mediump vec4 v_coords;\n";
347 if (loopCountType == LOOPCOUNT_DYNAMIC)
349 vtx << "layout(location=1) out mediump float v_one;\n";
350 frag << "layout(location=1) in mediump float v_one;\n";
354 const int numLoopIters = 3;
355 const bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
356 deUint32 locationCounter = 0;
357 std::vector<BaseUniformType> uniformInformations;
361 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
363 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
364 op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
366 uniformInformations.push_back(getIntUniformType(numLoopIters));
372 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
373 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
374 op << " ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
376 uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
380 if (numLoopIters != 1){
381 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
382 op << " ${COUNTER_PRECISION} float uf_one;\n";
384 uniformInformations.push_back(UF_ONE);
390 vtx << "void main()\n";
392 vtx << " gl_Position = a_position;\n";
395 frag << "void main()\n";
399 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
401 frag << " ${PRECISION} vec4 coords = v_coords;\n";
404 if (loopCountType == LOOPCOUNT_DYNAMIC)
409 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
411 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
416 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
418 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
423 op << " ${PRECISION} vec4 res = coords;\n";
425 // Loop iteration count.
426 std::string iterMaxStr;
430 if (loopCountType == LOOPCOUNT_CONSTANT)
431 iterMaxStr = de::toString(numLoopIters);
432 else if (loopCountType == LOOPCOUNT_UNIFORM)
433 iterMaxStr = getIntUniformName(numLoopIters);
434 else if (loopCountType == LOOPCOUNT_DYNAMIC)
435 iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
441 if (loopCountType == LOOPCOUNT_CONSTANT)
443 else if (loopCountType == LOOPCOUNT_UNIFORM)
444 iterMaxStr = "uf_one";
445 else if (loopCountType == LOOPCOUNT_DYNAMIC)
446 iterMaxStr = "uf_one*one";
452 std::string initValue = isIntCounter ? "0" : "0.05";
453 std::string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
454 std::string loopCmpStr = ("ndx < " + iterMaxStr);
455 std::string incrementStr;
457 incrementStr = "ndx++";
460 if (loopCountType == LOOPCOUNT_CONSTANT)
461 incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
462 else if (loopCountType == LOOPCOUNT_UNIFORM)
463 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
464 else if (loopCountType == LOOPCOUNT_DYNAMIC)
465 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
471 std::string loopBody;
473 loopBody = " res = res.yzwx;\n";
475 if (loopType == LOOPTYPE_FOR)
477 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
482 else if (loopType == LOOPTYPE_WHILE)
484 op << "\t" << loopCountDeclStr + ";\n";
485 op << " while (" + loopCmpStr + ")\n";
488 op << "\t\t" + incrementStr + ";\n";
491 else if (loopType == LOOPTYPE_DO_WHILE)
493 op << "\t" << loopCountDeclStr + ";\n";
497 op << "\t\t" + incrementStr + ";\n";
498 op << " } while (" + loopCmpStr + ");\n";
505 vtx << " v_color = res.rgb;\n";
506 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
510 vtx << " v_coords = a_coords;\n";
511 frag << " o_color = vec4(res.rgb, 1.0);\n";
513 if (loopCountType == LOOPCOUNT_DYNAMIC)
514 vtx << " v_one = a_one;\n";
520 // Fill in shader templates.
521 std::map<std::string, std::string> params;
522 params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
523 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
524 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
526 tcu::StringTemplate vertTemplate(vtx.str());
527 tcu::StringTemplate fragTemplate(frag.str());
528 std::string vertexShaderSource = vertTemplate.specialize(params);
529 std::string fragmentShaderSource = fragTemplate.specialize(params);
532 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
533 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
534 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
537 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext& testCtx,
538 const std::string& caseName,
539 const std::string& description,
543 LoopCountType loopCountType)
545 std::ostringstream vtx;
546 std::ostringstream frag;
547 std::ostringstream& op = isVertexCase ? vtx : frag;
549 std::vector<BaseUniformType> uniformInformations;
550 deUint32 locationCounter = 0;
552 vtx << "#version 140\n";
553 vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
554 vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
556 frag << "#version 140\n";
557 frag << "#extension GL_ARB_separate_shader_objects : enable\n";
558 frag << "#extension GL_ARB_shading_language_420pack : enable\n";
560 vtx << "layout(location=0) in highp vec4 a_position;\n";
561 vtx << "layout(location=1) in highp vec4 a_coords;\n";
562 frag << "layout(location=0) out mediump vec4 o_color;\n";
564 if (loopCountType == LOOPCOUNT_DYNAMIC)
565 vtx << "layout(location=3) in mediump float a_one;\n";
569 vtx << "layout(location=0) out mediump vec3 v_color;\n";
570 frag << "layout(location=0) in mediump vec3 v_color;\n";
574 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
575 frag << "layout(location=0) in mediump vec4 v_coords;\n";
577 if (loopCountType == LOOPCOUNT_DYNAMIC)
579 vtx << "layout(location=1) out mediump float v_one;\n";
580 frag << "layout(location=1) in mediump float v_one;\n";
584 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
585 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
586 op << " bool ub_true;\n";
588 uniformInformations.push_back(UB_TRUE);
595 BaseUniformType type;
598 { "ui_zero", UI_ZERO },
599 { "ui_one", UI_ONE },
600 { "ui_two", UI_TWO },
601 { "ui_three", UI_THREE },
602 { "ui_four", UI_FOUR },
603 { "ui_five", UI_FIVE },
604 { "ui_six", UI_SIX },
607 for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
609 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
610 op << " ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
612 uniformInformations.push_back(uniforms[i].type);
616 if (loopCase == LOOPCASE_101_ITERATIONS) {
618 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
619 op << " ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
621 uniformInformations.push_back(UI_ONEHUNDREDONE);
625 int iterCount = 3; // value to use in loop
626 int numIters = 3; // actual number of iterations
629 vtx << "void main()\n";
631 vtx << " gl_Position = a_position;\n";
634 frag << "void main()\n";
637 if (loopCountType == LOOPCOUNT_DYNAMIC)
640 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
642 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
646 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
648 frag << " ${PRECISION} vec4 coords = v_coords;\n";
651 op << " ${PRECISION} vec4 res = coords;\n";
653 // Handle all loop types.
654 std::string counterPrecisionStr = "mediump";
655 std::string forLoopStr;
656 std::string whileLoopStr;
657 std::string doWhileLoopPreStr;
658 std::string doWhileLoopPostStr;
660 if (loopType == LOOPTYPE_FOR)
664 case LOOPCASE_EMPTY_BODY:
666 op << " ${FOR_LOOP} {}\n";
669 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
671 op << " for (;;) { break; res = res.yzwx; }\n";
674 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
676 op << " for (;;) { res = res.yzwx; break; }\n";
679 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
681 op << " ${COUNTER_PRECISION} int i = 0;\n";
682 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
685 case LOOPCASE_SINGLE_STATEMENT:
686 op << " ${FOR_LOOP} res = res.yzwx;\n";
689 case LOOPCASE_COMPOUND_STATEMENT:
691 numIters = 2 * iterCount;
692 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
695 case LOOPCASE_SEQUENCE_STATEMENT:
697 numIters = 2 * iterCount;
698 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
701 case LOOPCASE_NO_ITERATIONS:
704 op << " ${FOR_LOOP} res = res.yzwx;\n";
707 case LOOPCASE_SINGLE_ITERATION:
710 op << " ${FOR_LOOP} res = res.yzwx;\n";
713 case LOOPCASE_SELECT_ITERATION_COUNT:
714 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
717 case LOOPCASE_CONDITIONAL_CONTINUE:
718 numIters = iterCount - 1;
719 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
722 case LOOPCASE_UNCONDITIONAL_CONTINUE:
723 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
726 case LOOPCASE_ONLY_CONTINUE:
728 op << " ${FOR_LOOP} { continue; }\n";
731 case LOOPCASE_DOUBLE_CONTINUE:
732 numIters = iterCount - 1;
733 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
736 case LOOPCASE_CONDITIONAL_BREAK:
738 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
741 case LOOPCASE_UNCONDITIONAL_BREAK:
743 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
746 case LOOPCASE_PRE_INCREMENT:
747 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
750 case LOOPCASE_POST_INCREMENT:
751 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
754 case LOOPCASE_MIXED_BREAK_CONTINUE:
757 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
760 case LOOPCASE_VECTOR_COUNTER:
761 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx; }\n";
764 case LOOPCASE_101_ITERATIONS:
765 numIters = iterCount = 101;
766 op << " ${FOR_LOOP} res = res.yzwx;\n";
769 case LOOPCASE_SEQUENCE:
772 op << " ${COUNTER_PRECISION} int i;\n";
773 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
774 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
777 case LOOPCASE_NESTED:
778 numIters = 2 * iterCount;
779 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
781 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
782 op << " res = res.yzwx;\n";
786 case LOOPCASE_NESTED_SEQUENCE:
787 numIters = 3 * iterCount;
788 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
790 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
791 op << " res = res.yzwx;\n";
792 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
793 op << " res = res.yzwx;\n";
797 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
799 op << " ${FOR_LOOP}\n";
801 op << " res = coords; // ignore outer loop effect \n";
802 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
803 op << " res = res.yzwx;\n";
807 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
808 numIters = iterCount;
809 op << " ${FOR_LOOP}\n";
811 op << " res = coords.wxyz;\n";
812 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
813 op << " res = res.yzwx;\n";
814 op << " coords = res;\n";
822 if (loopCountType == LOOPCOUNT_CONSTANT)
823 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
824 else if (loopCountType == LOOPCOUNT_UNIFORM)
825 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
826 else if (loopCountType == LOOPCOUNT_DYNAMIC)
827 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
831 else if (loopType == LOOPTYPE_WHILE)
835 case LOOPCASE_EMPTY_BODY:
837 op << " ${WHILE_LOOP} {}\n";
840 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
842 op << " while (true) { break; res = res.yzwx; }\n";
845 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
847 op << " while (true) { res = res.yzwx; break; }\n";
850 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
852 op << " ${COUNTER_PRECISION} int i = 0;\n";
853 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
856 case LOOPCASE_SINGLE_STATEMENT:
857 op << " ${WHILE_LOOP} res = res.yzwx;\n";
860 case LOOPCASE_COMPOUND_STATEMENT:
862 numIters = 2 * iterCount;
863 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
866 case LOOPCASE_SEQUENCE_STATEMENT:
868 numIters = 2 * iterCount;
869 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
872 case LOOPCASE_NO_ITERATIONS:
875 op << " ${WHILE_LOOP} res = res.yzwx;\n";
878 case LOOPCASE_SINGLE_ITERATION:
881 op << " ${WHILE_LOOP} res = res.yzwx;\n";
884 case LOOPCASE_SELECT_ITERATION_COUNT:
885 op << " ${COUNTER_PRECISION} int i = 0;\n";
886 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
889 case LOOPCASE_CONDITIONAL_CONTINUE:
890 numIters = iterCount - 1;
891 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
894 case LOOPCASE_UNCONDITIONAL_CONTINUE:
895 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
898 case LOOPCASE_ONLY_CONTINUE:
900 op << " ${WHILE_LOOP} { continue; }\n";
903 case LOOPCASE_DOUBLE_CONTINUE:
904 numIters = iterCount - 1;
905 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
908 case LOOPCASE_CONDITIONAL_BREAK:
910 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
913 case LOOPCASE_UNCONDITIONAL_BREAK:
915 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
918 case LOOPCASE_PRE_INCREMENT:
919 numIters = iterCount - 1;
920 op << " ${COUNTER_PRECISION} int i = 0;\n";
921 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
924 case LOOPCASE_POST_INCREMENT:
925 op << " ${COUNTER_PRECISION} int i = 0;\n";
926 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
929 case LOOPCASE_MIXED_BREAK_CONTINUE:
932 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
935 case LOOPCASE_VECTOR_COUNTER:
936 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
937 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
940 case LOOPCASE_101_ITERATIONS:
941 numIters = iterCount = 101;
942 op << " ${WHILE_LOOP} res = res.yzwx;\n";
945 case LOOPCASE_SEQUENCE:
947 numIters = iterCount - 1;
948 op << " ${COUNTER_PRECISION} int i = 0;\n";
949 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
950 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
953 case LOOPCASE_NESTED:
954 numIters = 2 * iterCount;
955 op << " ${COUNTER_PRECISION} int i = 0;\n";
956 op << " while (i++ < ${TWO})\n";
958 op << " ${COUNTER_PRECISION} int j = 0;\n";
959 op << " while (j++ < ${ITER_COUNT})\n";
960 op << " res = res.yzwx;\n";
964 case LOOPCASE_NESTED_SEQUENCE:
965 numIters = 2 * iterCount;
966 op << " ${COUNTER_PRECISION} int i = 0;\n";
967 op << " while (i++ < ${ITER_COUNT})\n";
969 op << " ${COUNTER_PRECISION} int j = 0;\n";
970 op << " while (j++ < ${ONE})\n";
971 op << " res = res.yzwx;\n";
972 op << " while (j++ < ${THREE})\n"; // \note skips one iteration
973 op << " res = res.yzwx;\n";
977 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
979 op << " ${WHILE_LOOP}\n";
981 op << " res = coords; // ignore outer loop effect \n";
982 op << " ${COUNTER_PRECISION} int j = 0;\n";
983 op << " while (j++ < ${TWO})\n";
984 op << " res = res.yzwx;\n";
988 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
989 numIters = iterCount;
990 op << " ${WHILE_LOOP}\n";
992 op << " res = coords.wxyz;\n";
993 op << " ${COUNTER_PRECISION} int j = 0;\n";
994 op << " while (j++ < ${TWO})\n";
995 op << " res = res.yzwx;\n";
996 op << " coords = res;\n";
1004 if (loopCountType == LOOPCOUNT_CONSTANT)
1005 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")";
1006 else if (loopCountType == LOOPCOUNT_UNIFORM)
1007 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + getIntUniformName(iterCount) + ")";
1008 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1009 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" + getIntUniformName(iterCount) + ")";
1015 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
1019 case LOOPCASE_EMPTY_BODY:
1021 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1024 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1026 op << " do { break; res = res.yzwx; } while (true);\n";
1029 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1031 op << " do { res = res.yzwx; break; } while (true);\n";
1034 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1036 op << " ${COUNTER_PRECISION} int i = 0;\n";
1037 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
1040 case LOOPCASE_SINGLE_STATEMENT:
1041 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1044 case LOOPCASE_COMPOUND_STATEMENT:
1046 numIters = 2 * iterCount;
1047 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
1050 case LOOPCASE_SEQUENCE_STATEMENT:
1052 numIters = 2 * iterCount;
1053 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
1056 case LOOPCASE_NO_ITERATIONS:
1060 case LOOPCASE_SINGLE_ITERATION:
1063 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1066 case LOOPCASE_SELECT_ITERATION_COUNT:
1067 op << " ${COUNTER_PRECISION} int i = 0;\n";
1068 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1071 case LOOPCASE_CONDITIONAL_CONTINUE:
1072 numIters = iterCount - 1;
1073 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
1076 case LOOPCASE_UNCONDITIONAL_CONTINUE:
1077 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1080 case LOOPCASE_ONLY_CONTINUE:
1082 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1085 case LOOPCASE_DOUBLE_CONTINUE:
1086 numIters = iterCount - 1;
1087 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1090 case LOOPCASE_CONDITIONAL_BREAK:
1092 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1095 case LOOPCASE_UNCONDITIONAL_BREAK:
1097 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
1100 case LOOPCASE_PRE_INCREMENT:
1101 op << " ${COUNTER_PRECISION} int i = 0;\n";
1102 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1105 case LOOPCASE_POST_INCREMENT:
1106 numIters = iterCount + 1;
1107 op << " ${COUNTER_PRECISION} int i = 0;\n";
1108 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
1111 case LOOPCASE_MIXED_BREAK_CONTINUE:
1114 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } ${DO_WHILE_POST}\n";
1117 case LOOPCASE_VECTOR_COUNTER:
1118 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1119 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1122 case LOOPCASE_101_ITERATIONS:
1123 numIters = iterCount = 101;
1124 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1127 case LOOPCASE_SEQUENCE:
1130 op << " ${COUNTER_PRECISION} int i = 0;\n";
1131 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
1132 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1135 case LOOPCASE_NESTED:
1136 numIters = 2 * iterCount;
1137 op << " ${COUNTER_PRECISION} int i = 0;\n";
1140 op << " ${COUNTER_PRECISION} int j = 0;\n";
1142 op << " res = res.yzwx;\n";
1143 op << " while (++j < ${ITER_COUNT});\n";
1144 op << " } while (++i < ${TWO});\n";
1147 case LOOPCASE_NESTED_SEQUENCE:
1148 numIters = 3 * iterCount;
1149 op << " ${COUNTER_PRECISION} int i = 0;\n";
1152 op << " ${COUNTER_PRECISION} int j = 0;\n";
1154 op << " res = res.yzwx;\n";
1155 op << " while (++j < ${TWO});\n";
1157 op << " res = res.yzwx;\n";
1158 op << " while (++j < ${THREE});\n";
1159 op << " } while (++i < ${ITER_COUNT});\n";
1162 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1164 op << " ${DO_WHILE_PRE}\n";
1166 op << " res = coords; // ignore outer loop effect \n";
1167 op << " ${COUNTER_PRECISION} int j = 0;\n";
1169 op << " res = res.yzwx;\n";
1170 op << " while (++j < ${TWO});\n";
1171 op << " } ${DO_WHILE_POST}\n";
1174 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1175 numIters = iterCount;
1176 op << " ${DO_WHILE_PRE}\n";
1178 op << " res = coords.wxyz;\n";
1179 op << " ${COUNTER_PRECISION} int j = 0;\n";
1180 op << " while (j++ < ${TWO})\n";
1181 op << " res = res.yzwx;\n";
1182 op << " coords = res;\n";
1183 op << " } ${DO_WHILE_POST}\n";
1190 doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1191 if (loopCountType == LOOPCOUNT_CONSTANT)
1192 doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1193 else if (loopCountType == LOOPCOUNT_UNIFORM)
1194 doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1195 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1196 doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1204 vtx << " v_color = res.rgb;\n";
1205 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
1209 vtx << " v_coords = a_coords;\n";
1210 frag << " o_color = vec4(res.rgb, 1.0);\n";
1212 if (loopCountType == LOOPCOUNT_DYNAMIC)
1213 vtx << " v_one = a_one;\n";
1222 std::string threeStr;
1223 std::string iterCountStr;
1225 if (loopCountType == LOOPCOUNT_CONSTANT)
1230 iterCountStr = de::toString(iterCount);
1232 else if (loopCountType == LOOPCOUNT_UNIFORM)
1236 threeStr = "ui_three";
1237 iterCountStr = getIntUniformName(iterCount);
1239 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1241 oneStr = "one*ui_one";
1242 twoStr = "one*ui_two";
1243 threeStr = "one*ui_three";
1244 iterCountStr = std::string("one*") + getIntUniformName(iterCount);
1246 else DE_ASSERT(false);
1248 // Fill in shader templates.
1249 std::map<std::string, std::string> params;
1250 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1251 params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1252 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1253 params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1254 params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1255 params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1256 params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1257 params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1258 params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1259 params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1261 tcu::StringTemplate vertTemplate(vtx.str());
1262 tcu::StringTemplate fragTemplate(frag.str());
1263 std::string vertexShaderSource = vertTemplate.specialize(params);
1264 std::string fragmentShaderSource = fragTemplate.specialize(params);
1267 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1268 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1269 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1272 class ShaderLoopTests : public tcu::TestCaseGroup
1275 ShaderLoopTests (tcu::TestContext& testCtx);
1276 virtual ~ShaderLoopTests (void);
1278 virtual void init (void);
1281 ShaderLoopTests (const ShaderLoopTests&); // not allowed!
1282 ShaderLoopTests& operator= (const ShaderLoopTests&); // not allowed!
1285 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1286 : TestCaseGroup(testCtx, "loops", "Loop Tests")
1290 ShaderLoopTests::~ShaderLoopTests (void)
1294 void ShaderLoopTests::init (void)
1298 static const glu::ShaderType s_shaderTypes[] =
1300 glu::SHADERTYPE_VERTEX,
1301 glu::SHADERTYPE_FRAGMENT
1304 static const glu::DataType s_countDataType[] =
1310 TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
1311 TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
1312 addChild(genericGroup);
1313 addChild(specialGroup);
1315 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1317 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1319 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1321 const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1323 std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1324 std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1325 TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1326 TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1327 genericGroup->addChild(genericSubGroup);
1328 specialGroup->addChild(specialSubGroup);
1332 for (int precision = 0; precision < glu::PRECISION_LAST; precision++)
1334 const char* precisionName = getPrecisionName((glu::Precision)precision);
1336 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1338 glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1339 const char* dataTypeName = getDataTypeName(loopDataType);
1341 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1343 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1344 const char* shaderTypeName = getShaderTypeName(shaderType);
1345 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1347 std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1348 std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
1349 de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1350 genericSubGroup->addChild(testCase.release());
1357 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1359 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1361 // no-iterations not possible with do-while.
1362 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1365 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1367 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1368 const char* shaderTypeName = getShaderTypeName(shaderType);
1369 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1371 std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1372 std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
1373 de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1374 specialSubGroup->addChild(testCase.release());
1383 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1385 return new ShaderLoopTests(testCtx);