1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Shader loop tests.
22 *
23 * \todo [petri]
24 * - loop body cases (do different operations inside the loops)
25 * - more complex nested loops
26 * * random generated?
27 * * dataflow variations
28 * * mixed loop types
29 * -
30 *//*--------------------------------------------------------------------*/
31
32 #include "es2fShaderLoopTests.hpp"
33 #include "glsShaderLibrary.hpp"
34 #include "glsShaderRenderCase.hpp"
35 #include "gluShaderUtil.hpp"
36 #include "tcuStringTemplate.hpp"
37
38 #include "deStringUtil.hpp"
39 #include "deInt32.h"
40 #include "deMemory.h"
41
42 #include <map>
43
44 using namespace std;
45 using namespace tcu;
46 using namespace glu;
47 using namespace deqp::gls;
48
49 namespace deqp
50 {
51 namespace gles2
52 {
53 namespace Functional
54 {
55
56 // Repeated with for, while, do-while. Examples given as 'for' loops.
57 // Repeated for const, uniform, dynamic loops.
58 enum LoopCase
59 {
60 LOOPCASE_EMPTY_BODY = 0, // for (...) { }
61 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
62 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
63 LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
64 LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
65 LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
66 LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
67 LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
68 LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
69 LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
70 LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
71 LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
72 LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
73 LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; continue; }
74 LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
75 LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
76 LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
77 LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
78 LOOPCASE_MIXED_BREAK_CONTINUE,
79 LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx.x += ndx.z) { ... }
80 LOOPCASE_101_ITERATIONS, // loop for 101 iterations
81 LOOPCASE_SEQUENCE, // two loops in sequence
82 LOOPCASE_NESTED, // two nested loops
83 LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a third
84 LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
85 LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
86 LOOPCASE_CONDITIONAL_BODY, // conditional body in loop
87 LOOPCASE_FUNCTION_CALL_RETURN, // function call in loop with return value usage
88 LOOPCASE_FUNCTION_CALL_INOUT, // function call with inout parameter usage
89
90 LOOPCASE_LAST
91 };
92
93 enum LoopRequirement
94 {
95 LOOPREQUIREMENT_STANDARD = 0, //!< Minimum requirements by standard (constant for loop with simple iterator).
96 LOOPREQUIREMENT_UNIFORM,
97 LOOPREQUIREMENT_DYNAMIC,
98
99 LOOPREQUIREMENT_LAST
100 };
101
getLoopCaseName(LoopCase loopCase)102 static const char *getLoopCaseName(LoopCase loopCase)
103 {
104 static const char *s_names[] = {"empty_body",
105 "infinite_with_unconditional_break_first",
106 "infinite_with_unconditional_break_last",
107 "infinite_with_conditional_break",
108 "single_statement",
109 "compound_statement",
110 "sequence_statement",
111 "no_iterations",
112 "single_iteration",
113 "select_iteration_count",
114 "conditional_continue",
115 "unconditional_continue",
116 "only_continue",
117 "double_continue",
118 "conditional_break",
119 "unconditional_break",
120 "pre_increment",
121 "post_increment",
122 "mixed_break_continue",
123 "vector_counter",
124 "101_iterations",
125 "sequence",
126 "nested",
127 "nested_sequence",
128 "nested_tricky_dataflow_1",
129 "nested_tricky_dataflow_2",
130 "conditional_body",
131 "function_call_return",
132 "function_call_inout"};
133
134 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
135 DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
136 return s_names[(int)loopCase];
137 }
138
139 enum LoopType
140 {
141 LOOPTYPE_FOR = 0,
142 LOOPTYPE_WHILE,
143 LOOPTYPE_DO_WHILE,
144
145 LOOPTYPE_LAST
146 };
147
getLoopTypeName(LoopType loopType)148 static const char *getLoopTypeName(LoopType loopType)
149 {
150 static const char *s_names[] = {"for", "while", "do_while"};
151
152 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
153 DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
154 return s_names[(int)loopType];
155 }
156
157 enum LoopCountType
158 {
159 LOOPCOUNT_CONSTANT = 0,
160 LOOPCOUNT_UNIFORM,
161 LOOPCOUNT_DYNAMIC,
162
163 LOOPCOUNT_LAST
164 };
165
getLoopCountTypeName(LoopCountType countType)166 static const char *getLoopCountTypeName(LoopCountType countType)
167 {
168 static const char *s_names[] = {"constant", "uniform", "dynamic"};
169
170 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
171 DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
172 return s_names[(int)countType];
173 }
174
evalLoop0Iters(ShaderEvalContext & c)175 static void evalLoop0Iters(ShaderEvalContext &c)
176 {
177 c.color.xyz() = c.coords.swizzle(0, 1, 2);
178 }
evalLoop1Iters(ShaderEvalContext & c)179 static void evalLoop1Iters(ShaderEvalContext &c)
180 {
181 c.color.xyz() = c.coords.swizzle(1, 2, 3);
182 }
evalLoop2Iters(ShaderEvalContext & c)183 static void evalLoop2Iters(ShaderEvalContext &c)
184 {
185 c.color.xyz() = c.coords.swizzle(2, 3, 0);
186 }
evalLoop3Iters(ShaderEvalContext & c)187 static void evalLoop3Iters(ShaderEvalContext &c)
188 {
189 c.color.xyz() = c.coords.swizzle(3, 0, 1);
190 }
191
getLoopEvalFunc(int numIters)192 static ShaderEvalFunc getLoopEvalFunc(int numIters)
193 {
194 switch (numIters % 4)
195 {
196 case 0:
197 return evalLoop0Iters;
198 case 1:
199 return evalLoop1Iters;
200 case 2:
201 return evalLoop2Iters;
202 case 3:
203 return evalLoop3Iters;
204 }
205
206 DE_FATAL("Invalid loop iteration count.");
207 return NULL;
208 }
209
210 // ShaderLoopCase
211
212 class ShaderLoopCase : public ShaderRenderCase
213 {
214 public:
215 ShaderLoopCase(Context &context, const char *name, const char *description, bool isVertexCase,
216 ShaderEvalFunc evalFunc, LoopRequirement requirement, const char *vertShaderSource,
217 const char *fragShaderSource);
218 virtual ~ShaderLoopCase(void);
219
220 void init(void);
221
222 private:
223 ShaderLoopCase(const ShaderLoopCase &); // not allowed!
224 ShaderLoopCase &operator=(const ShaderLoopCase &); // not allowed!
225
226 virtual void setup(int programID);
227 virtual void setupUniforms(int programID, const Vec4 &constCoords);
228
229 LoopRequirement m_requirement;
230 };
231
ShaderLoopCase(Context & context,const char * name,const char * description,bool isVertexCase,ShaderEvalFunc evalFunc,LoopRequirement requirement,const char * vertShaderSource,const char * fragShaderSource)232 ShaderLoopCase::ShaderLoopCase(Context &context, const char *name, const char *description, bool isVertexCase,
233 ShaderEvalFunc evalFunc, LoopRequirement requirement, const char *vertShaderSource,
234 const char *fragShaderSource)
235 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
236 description, isVertexCase, evalFunc)
237 , m_requirement(requirement)
238 {
239 m_vertShaderSource = vertShaderSource;
240 m_fragShaderSource = fragShaderSource;
241 }
242
~ShaderLoopCase(void)243 ShaderLoopCase::~ShaderLoopCase(void)
244 {
245 }
246
init(void)247 void ShaderLoopCase::init(void)
248 {
249 bool isSupported = true;
250
251 if (m_requirement == LOOPREQUIREMENT_UNIFORM)
252 isSupported =
253 m_isVertexCase ? m_ctxInfo.isVertexUniformLoopSupported() : m_ctxInfo.isFragmentUniformLoopSupported();
254 else if (m_requirement == LOOPREQUIREMENT_DYNAMIC)
255 isSupported =
256 m_isVertexCase ? m_ctxInfo.isVertexDynamicLoopSupported() : m_ctxInfo.isFragmentDynamicLoopSupported();
257
258 try
259 {
260 ShaderRenderCase::init();
261 }
262 catch (const CompileFailed &)
263 {
264 if (!isSupported)
265 throw tcu::NotSupportedError("Loop type is not supported");
266 else
267 throw;
268 }
269 }
270
setup(int programID)271 void ShaderLoopCase::setup(int programID)
272 {
273 DE_UNREF(programID);
274 }
275
setupUniforms(int programID,const Vec4 & constCoords)276 void ShaderLoopCase::setupUniforms(int programID, const Vec4 &constCoords)
277 {
278 DE_UNREF(programID);
279 DE_UNREF(constCoords);
280 }
281
282 // Test case creation.
283
createGenericLoopCase(Context & context,const char * caseName,const char * description,bool isVertexCase,LoopType loopType,LoopCountType loopCountType,Precision loopCountPrecision,DataType loopCountDataType)284 static ShaderLoopCase *createGenericLoopCase(Context &context, const char *caseName, const char *description,
285 bool isVertexCase, LoopType loopType, LoopCountType loopCountType,
286 Precision loopCountPrecision, DataType loopCountDataType)
287 {
288 std::ostringstream vtx;
289 std::ostringstream frag;
290 std::ostringstream &op = isVertexCase ? vtx : frag;
291
292 vtx << "attribute highp vec4 a_position;\n";
293 vtx << "attribute highp vec4 a_coords;\n";
294
295 if (loopCountType == LOOPCOUNT_DYNAMIC)
296 vtx << "attribute mediump float a_one;\n";
297
298 if (isVertexCase)
299 {
300 vtx << "varying mediump vec3 v_color;\n";
301 frag << "varying mediump vec3 v_color;\n";
302 }
303 else
304 {
305 vtx << "varying mediump vec4 v_coords;\n";
306 frag << "varying mediump vec4 v_coords;\n";
307
308 if (loopCountType == LOOPCOUNT_DYNAMIC)
309 {
310 vtx << "varying mediump float v_one;\n";
311 frag << "varying mediump float v_one;\n";
312 }
313 }
314
315 // \todo [petri] Pass numLoopIters from outside?
316 int numLoopIters = 3;
317 bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
318
319 if (isIntCounter)
320 {
321 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
322 op << "uniform ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
323 }
324 else
325 {
326 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
327 op << "uniform ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
328
329 if (numLoopIters != 1)
330 op << "uniform ${COUNTER_PRECISION} float uf_one;\n";
331 }
332
333 vtx << "\n";
334 vtx << "void main()\n";
335 vtx << "{\n";
336 vtx << " gl_Position = a_position;\n";
337
338 frag << "\n";
339 frag << "void main()\n";
340 frag << "{\n";
341
342 if (isVertexCase)
343 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
344 else
345 frag << " ${PRECISION} vec4 coords = v_coords;\n";
346
347 if (loopCountType == LOOPCOUNT_DYNAMIC)
348 {
349 if (isIntCounter)
350 {
351 if (isVertexCase)
352 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
353 else
354 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
355 }
356 else
357 {
358 if (isVertexCase)
359 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
360 else
361 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
362 }
363 }
364
365 // Read array.
366 op << " ${PRECISION} vec4 res = coords;\n";
367
368 // Loop iteration count.
369 string iterMaxStr;
370
371 if (isIntCounter)
372 {
373 if (loopCountType == LOOPCOUNT_CONSTANT)
374 iterMaxStr = de::toString(numLoopIters);
375 else if (loopCountType == LOOPCOUNT_UNIFORM)
376 iterMaxStr = getIntUniformName(numLoopIters);
377 else if (loopCountType == LOOPCOUNT_DYNAMIC)
378 iterMaxStr = string(getIntUniformName(numLoopIters)) + "*one";
379 else
380 DE_ASSERT(false);
381 }
382 else
383 {
384 if (loopCountType == LOOPCOUNT_CONSTANT)
385 iterMaxStr = "1.0";
386 else if (loopCountType == LOOPCOUNT_UNIFORM)
387 iterMaxStr = "uf_one";
388 else if (loopCountType == LOOPCOUNT_DYNAMIC)
389 iterMaxStr = "uf_one*one";
390 else
391 DE_ASSERT(false);
392 }
393
394 // Loop operations.
395 string initValue = isIntCounter ? "0" : "0.05";
396 string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
397 string loopCmpStr = ("ndx < " + iterMaxStr);
398 string incrementStr;
399 if (isIntCounter)
400 incrementStr = "ndx++";
401 else
402 {
403 if (loopCountType == LOOPCOUNT_CONSTANT)
404 incrementStr = string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
405 else if (loopCountType == LOOPCOUNT_UNIFORM)
406 incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters);
407 else if (loopCountType == LOOPCOUNT_DYNAMIC)
408 incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
409 else
410 DE_ASSERT(false);
411 }
412
413 // Loop body.
414 string loopBody;
415
416 loopBody = " res = res.yzwx;\n";
417
418 if (loopType == LOOPTYPE_FOR)
419 {
420 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
421 op << " {\n";
422 op << loopBody;
423 op << " }\n";
424 }
425 else if (loopType == LOOPTYPE_WHILE)
426 {
427 op << "\t" << loopCountDeclStr + ";\n";
428 op << " while (" + loopCmpStr + ")\n";
429 op << " {\n";
430 op << loopBody;
431 op << "\t\t" + incrementStr + ";\n";
432 op << " }\n";
433 }
434 else if (loopType == LOOPTYPE_DO_WHILE)
435 {
436 op << "\t" << loopCountDeclStr + ";\n";
437 op << " do\n";
438 op << " {\n";
439 op << loopBody;
440 op << "\t\t" + incrementStr + ";\n";
441 op << " } while (" + loopCmpStr + ");\n";
442 }
443 else
444 DE_ASSERT(false);
445
446 if (isVertexCase)
447 {
448 vtx << " v_color = res.rgb;\n";
449 frag << " gl_FragColor = vec4(v_color.rgb, 1.0);\n";
450 }
451 else
452 {
453 vtx << " v_coords = a_coords;\n";
454 frag << " gl_FragColor = vec4(res.rgb, 1.0);\n";
455
456 if (loopCountType == LOOPCOUNT_DYNAMIC)
457 vtx << " v_one = a_one;\n";
458 }
459
460 vtx << "}\n";
461 frag << "}\n";
462
463 // Fill in shader templates.
464 map<string, string> params;
465 params.insert(pair<string, string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
466 params.insert(pair<string, string>("PRECISION", "mediump"));
467 params.insert(pair<string, string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
468
469 StringTemplate vertTemplate(vtx.str().c_str());
470 StringTemplate fragTemplate(frag.str().c_str());
471 string vertexShaderSource = vertTemplate.specialize(params);
472 string fragmentShaderSource = fragTemplate.specialize(params);
473
474 // Create the case.
475 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
476 LoopRequirement requirement;
477
478 if (loopType == LOOPTYPE_FOR)
479 {
480 if (loopCountType == LOOPCOUNT_CONSTANT)
481 requirement = LOOPREQUIREMENT_STANDARD;
482 else if (loopCountType == LOOPCOUNT_UNIFORM)
483 requirement = LOOPREQUIREMENT_UNIFORM;
484 else
485 requirement = LOOPREQUIREMENT_DYNAMIC;
486 }
487 else
488 requirement = LOOPREQUIREMENT_DYNAMIC;
489
490 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, requirement,
491 vertexShaderSource.c_str(), fragmentShaderSource.c_str());
492 }
493
494 // \todo [petri] Generalize to float as well?
createSpecialLoopCase(Context & context,const char * caseName,const char * description,bool isVertexCase,LoopCase loopCase,LoopType loopType,LoopCountType loopCountType)495 static ShaderLoopCase *createSpecialLoopCase(Context &context, const char *caseName, const char *description,
496 bool isVertexCase, LoopCase loopCase, LoopType loopType,
497 LoopCountType loopCountType)
498 {
499 std::ostringstream vtx;
500 std::ostringstream frag;
501 std::ostringstream &op = isVertexCase ? vtx : frag;
502
503 vtx << "attribute highp vec4 a_position;\n";
504 vtx << "attribute highp vec4 a_coords;\n";
505
506 if (loopCountType == LOOPCOUNT_DYNAMIC)
507 vtx << "attribute mediump float a_one;\n";
508
509 // Attribute and varyings.
510 if (isVertexCase)
511 {
512 vtx << "varying mediump vec3 v_color;\n";
513 frag << "varying mediump vec3 v_color;\n";
514 }
515 else
516 {
517 vtx << "varying mediump vec4 v_coords;\n";
518 frag << "varying mediump vec4 v_coords;\n";
519
520 if (loopCountType == LOOPCOUNT_DYNAMIC)
521 {
522 vtx << "varying mediump float v_one;\n";
523 frag << "varying mediump float v_one;\n";
524 }
525 }
526
527 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT)
528 op << "uniform bool ub_true;\n";
529
530 op << "uniform ${COUNTER_PRECISION} int ui_zero, ui_one, ui_two, ui_three, ui_four, ui_five, ui_six;\n";
531 if (loopCase == LOOPCASE_101_ITERATIONS)
532 op << "uniform ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
533
534 int iterCount = 3; // value to use in loop
535 int numIters = 3; // actual number of iterations
536
537 // Generate helpers if necessary.
538 if (loopCase == LOOPCASE_FUNCTION_CALL_RETURN)
539 op << "\n${PRECISION} vec4 func (in ${PRECISION} vec4 coords) { return coords.yzwx; }\n";
540 else if (loopCase == LOOPCASE_FUNCTION_CALL_INOUT)
541 op << "\nvoid func (inout ${PRECISION} vec4 coords) { coords = coords.yzwx; }\n";
542
543 vtx << "\n";
544 vtx << "void main()\n";
545 vtx << "{\n";
546 vtx << " gl_Position = a_position;\n";
547
548 frag << "\n";
549 frag << "void main()\n";
550 frag << "{\n";
551
552 if (loopCountType == LOOPCOUNT_DYNAMIC)
553 {
554 if (isVertexCase)
555 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
556 else
557 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
558 }
559
560 if (isVertexCase)
561 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
562 else
563 frag << " ${PRECISION} vec4 coords = v_coords;\n";
564
565 // Read array.
566 op << " ${PRECISION} vec4 res = coords;\n";
567
568 // Handle all loop types.
569 string counterPrecisionStr = "mediump";
570 string forLoopStr;
571 string whileLoopStr;
572 string doWhileLoopPreStr;
573 string doWhileLoopPostStr;
574
575 if (loopType == LOOPTYPE_FOR)
576 {
577 switch (loopCase)
578 {
579 case LOOPCASE_EMPTY_BODY:
580 numIters = 0;
581 op << " ${FOR_LOOP} {}\n";
582 break;
583
584 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
585 numIters = 0;
586 op << " for (;;) { break; res = res.yzwx; }\n";
587 break;
588
589 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
590 numIters = 1;
591 op << " for (;;) { res = res.yzwx; break; }\n";
592 break;
593
594 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
595 numIters = 2;
596 op << " ${COUNTER_PRECISION} int i = 0;\n";
597 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
598 break;
599
600 case LOOPCASE_SINGLE_STATEMENT:
601 op << " ${FOR_LOOP} res = res.yzwx;\n";
602 break;
603
604 case LOOPCASE_COMPOUND_STATEMENT:
605 iterCount = 2;
606 numIters = 2 * iterCount;
607 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
608 break;
609
610 case LOOPCASE_SEQUENCE_STATEMENT:
611 iterCount = 2;
612 numIters = 2 * iterCount;
613 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
614 break;
615
616 case LOOPCASE_NO_ITERATIONS:
617 iterCount = 0;
618 numIters = 0;
619 op << " ${FOR_LOOP} res = res.yzwx;\n";
620 break;
621
622 case LOOPCASE_SINGLE_ITERATION:
623 iterCount = 1;
624 numIters = 1;
625 op << " ${FOR_LOOP} res = res.yzwx;\n";
626 break;
627
628 case LOOPCASE_SELECT_ITERATION_COUNT:
629 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
630 break;
631
632 case LOOPCASE_CONDITIONAL_CONTINUE:
633 numIters = iterCount - 1;
634 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
635 break;
636
637 case LOOPCASE_UNCONDITIONAL_CONTINUE:
638 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
639 break;
640
641 case LOOPCASE_ONLY_CONTINUE:
642 numIters = 0;
643 op << " ${FOR_LOOP} { continue; }\n";
644 break;
645
646 case LOOPCASE_DOUBLE_CONTINUE:
647 numIters = iterCount - 1;
648 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
649 break;
650
651 case LOOPCASE_CONDITIONAL_BREAK:
652 numIters = 2;
653 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
654 break;
655
656 case LOOPCASE_UNCONDITIONAL_BREAK:
657 numIters = 1;
658 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
659 break;
660
661 case LOOPCASE_PRE_INCREMENT:
662 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
663 break;
664
665 case LOOPCASE_POST_INCREMENT:
666 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
667 break;
668
669 case LOOPCASE_MIXED_BREAK_CONTINUE:
670 numIters = 2;
671 iterCount = 5;
672 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
673 break;
674
675 case LOOPCASE_VECTOR_COUNTER:
676 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res "
677 "= "
678 "res.yzwx; }\n";
679 break;
680
681 case LOOPCASE_101_ITERATIONS:
682 numIters = iterCount = 101;
683 op << " ${FOR_LOOP} res = res.yzwx;\n";
684 break;
685
686 case LOOPCASE_SEQUENCE:
687 iterCount = 5;
688 numIters = 5;
689 op << " ${COUNTER_PRECISION} int i;\n";
690 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
691 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
692 break;
693
694 case LOOPCASE_NESTED:
695 numIters = 2 * iterCount;
696 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
697 op << " {\n";
698 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
699 op << " res = res.yzwx;\n";
700 op << " }\n";
701 break;
702
703 case LOOPCASE_NESTED_SEQUENCE:
704 numIters = 3 * iterCount;
705 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
706 op << " {\n";
707 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
708 op << " res = res.yzwx;\n";
709 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
710 op << " res = res.yzwx;\n";
711 op << " }\n";
712 break;
713
714 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
715 numIters = 2;
716 op << " ${FOR_LOOP}\n";
717 op << " {\n";
718 op << " res = coords; // ignore outer loop effect \n";
719 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
720 op << " res = res.yzwx;\n";
721 op << " }\n";
722 break;
723
724 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
725 numIters = iterCount;
726 op << " ${FOR_LOOP}\n";
727 op << " {\n";
728 op << " res = coords.wxyz;\n";
729 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
730 op << " res = res.yzwx;\n";
731 op << " coords = res;\n";
732 op << " }\n";
733 break;
734
735 case LOOPCASE_CONDITIONAL_BODY:
736 numIters = de::min(2, iterCount);
737 op << " ${FOR_LOOP} if (i < 2) res = res.yzwx;\n";
738 break;
739
740 case LOOPCASE_FUNCTION_CALL_RETURN:
741 numIters = iterCount;
742 op << " ${FOR_LOOP}\n";
743 op << " {\n";
744 op << " res = func(res);\n";
745 op << " }\n";
746 break;
747
748 case LOOPCASE_FUNCTION_CALL_INOUT:
749 numIters = iterCount;
750 op << " ${FOR_LOOP}\n";
751 op << " {\n";
752 op << " func(res);\n";
753 op << " }\n";
754 break;
755
756 default:
757 DE_ASSERT(false);
758 }
759
760 if (loopCountType == LOOPCOUNT_CONSTANT)
761 forLoopStr =
762 string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
763 else if (loopCountType == LOOPCOUNT_UNIFORM)
764 forLoopStr =
765 string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
766 else if (loopCountType == LOOPCOUNT_DYNAMIC)
767 forLoopStr = string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) +
768 "; i++)";
769 else
770 DE_ASSERT(false);
771 }
772 else if (loopType == LOOPTYPE_WHILE)
773 {
774 switch (loopCase)
775 {
776 case LOOPCASE_EMPTY_BODY:
777 numIters = 0;
778 op << " ${WHILE_LOOP} {}\n";
779 break;
780
781 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
782 numIters = 0;
783 op << " while (true) { break; res = res.yzwx; }\n";
784 break;
785
786 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
787 numIters = 1;
788 op << " while (true) { res = res.yzwx; break; }\n";
789 break;
790
791 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
792 numIters = 2;
793 op << " ${COUNTER_PRECISION} int i = 0;\n";
794 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
795 break;
796
797 case LOOPCASE_SINGLE_STATEMENT:
798 op << " ${WHILE_LOOP} res = res.yzwx;\n";
799 break;
800
801 case LOOPCASE_COMPOUND_STATEMENT:
802 iterCount = 2;
803 numIters = 2 * iterCount;
804 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
805 break;
806
807 case LOOPCASE_SEQUENCE_STATEMENT:
808 iterCount = 2;
809 numIters = 2 * iterCount;
810 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
811 break;
812
813 case LOOPCASE_NO_ITERATIONS:
814 iterCount = 0;
815 numIters = 0;
816 op << " ${WHILE_LOOP} res = res.yzwx;\n";
817 break;
818
819 case LOOPCASE_SINGLE_ITERATION:
820 iterCount = 1;
821 numIters = 1;
822 op << " ${WHILE_LOOP} res = res.yzwx;\n";
823 break;
824
825 case LOOPCASE_SELECT_ITERATION_COUNT:
826 op << " ${COUNTER_PRECISION} int i = 0;\n";
827 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
828 break;
829
830 case LOOPCASE_CONDITIONAL_CONTINUE:
831 numIters = iterCount - 1;
832 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
833 break;
834
835 case LOOPCASE_UNCONDITIONAL_CONTINUE:
836 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
837 break;
838
839 case LOOPCASE_ONLY_CONTINUE:
840 numIters = 0;
841 op << " ${WHILE_LOOP} { continue; }\n";
842 break;
843
844 case LOOPCASE_DOUBLE_CONTINUE:
845 numIters = iterCount - 1;
846 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
847 break;
848
849 case LOOPCASE_CONDITIONAL_BREAK:
850 numIters = 2;
851 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
852 break;
853
854 case LOOPCASE_UNCONDITIONAL_BREAK:
855 numIters = 1;
856 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
857 break;
858
859 case LOOPCASE_PRE_INCREMENT:
860 numIters = iterCount - 1;
861 op << " ${COUNTER_PRECISION} int i = 0;\n";
862 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
863 break;
864
865 case LOOPCASE_POST_INCREMENT:
866 op << " ${COUNTER_PRECISION} int i = 0;\n";
867 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
868 break;
869
870 case LOOPCASE_MIXED_BREAK_CONTINUE:
871 numIters = 2;
872 iterCount = 5;
873 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
874 break;
875
876 case LOOPCASE_VECTOR_COUNTER:
877 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
878 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
879 break;
880
881 case LOOPCASE_101_ITERATIONS:
882 numIters = iterCount = 101;
883 op << " ${WHILE_LOOP} res = res.yzwx;\n";
884 break;
885
886 case LOOPCASE_SEQUENCE:
887 iterCount = 6;
888 numIters = iterCount - 1;
889 op << " ${COUNTER_PRECISION} int i = 0;\n";
890 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
891 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
892 break;
893
894 case LOOPCASE_NESTED:
895 numIters = 2 * iterCount;
896 op << " ${COUNTER_PRECISION} int i = 0;\n";
897 op << " while (i++ < ${TWO})\n";
898 op << " {\n";
899 op << " ${COUNTER_PRECISION} int j = 0;\n";
900 op << " while (j++ < ${ITER_COUNT})\n";
901 op << " res = res.yzwx;\n";
902 op << " }\n";
903 break;
904
905 case LOOPCASE_NESTED_SEQUENCE:
906 numIters = 2 * iterCount;
907 op << " ${COUNTER_PRECISION} int i = 0;\n";
908 op << " while (i++ < ${ITER_COUNT})\n";
909 op << " {\n";
910 op << " ${COUNTER_PRECISION} int j = 0;\n";
911 op << " while (j++ < ${ONE})\n";
912 op << " res = res.yzwx;\n";
913 op << " while (j++ < ${THREE})\n"; // \note skips one iteration
914 op << " res = res.yzwx;\n";
915 op << " }\n";
916 break;
917
918 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
919 numIters = 2;
920 op << " ${WHILE_LOOP}\n";
921 op << " {\n";
922 op << " res = coords; // ignore outer loop effect \n";
923 op << " ${COUNTER_PRECISION} int j = 0;\n";
924 op << " while (j++ < ${TWO})\n";
925 op << " res = res.yzwx;\n";
926 op << " }\n";
927 break;
928
929 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
930 numIters = iterCount;
931 op << " ${WHILE_LOOP}\n";
932 op << " {\n";
933 op << " res = coords.wxyz;\n";
934 op << " ${COUNTER_PRECISION} int j = 0;\n";
935 op << " while (j++ < ${TWO})\n";
936 op << " res = res.yzwx;\n";
937 op << " coords = res;\n";
938 op << " }\n";
939 break;
940
941 case LOOPCASE_CONDITIONAL_BODY:
942 numIters = de::min(1, iterCount);
943 op << " ${WHILE_LOOP} if (i < 2) res = res.yzwx;\n";
944 break;
945
946 case LOOPCASE_FUNCTION_CALL_RETURN:
947 numIters = iterCount;
948 op << " ${WHILE_LOOP}\n";
949 op << " {\n";
950 op << " res = func(res);\n";
951 op << " }\n";
952 break;
953
954 case LOOPCASE_FUNCTION_CALL_INOUT:
955 numIters = iterCount;
956 op << " ${WHILE_LOOP}\n";
957 op << " {\n";
958 op << " func(res);\n";
959 op << " }\n";
960 break;
961
962 default:
963 DE_ASSERT(false);
964 }
965
966 if (loopCountType == LOOPCOUNT_CONSTANT)
967 whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " +
968 de::toString(iterCount) + ")";
969 else if (loopCountType == LOOPCOUNT_UNIFORM)
970 whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " +
971 getIntUniformName(iterCount) + ")";
972 else if (loopCountType == LOOPCOUNT_DYNAMIC)
973 whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" +
974 getIntUniformName(iterCount) + ")";
975 else
976 DE_ASSERT(false);
977 }
978 else
979 {
980 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
981
982 switch (loopCase)
983 {
984 case LOOPCASE_EMPTY_BODY:
985 numIters = 0;
986 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
987 break;
988
989 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
990 numIters = 0;
991 op << " do { break; res = res.yzwx; } while (true);\n";
992 break;
993
994 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
995 numIters = 1;
996 op << " do { res = res.yzwx; break; } while (true);\n";
997 break;
998
999 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1000 numIters = 2;
1001 op << " ${COUNTER_PRECISION} int i = 0;\n";
1002 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
1003 break;
1004
1005 case LOOPCASE_SINGLE_STATEMENT:
1006 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1007 break;
1008
1009 case LOOPCASE_COMPOUND_STATEMENT:
1010 iterCount = 2;
1011 numIters = 2 * iterCount;
1012 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
1013 break;
1014
1015 case LOOPCASE_SEQUENCE_STATEMENT:
1016 iterCount = 2;
1017 numIters = 2 * iterCount;
1018 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
1019 break;
1020
1021 case LOOPCASE_NO_ITERATIONS:
1022 DE_ASSERT(false);
1023 break;
1024
1025 case LOOPCASE_SINGLE_ITERATION:
1026 iterCount = 1;
1027 numIters = 1;
1028 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1029 break;
1030
1031 case LOOPCASE_SELECT_ITERATION_COUNT:
1032 op << " ${COUNTER_PRECISION} int i = 0;\n";
1033 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1034 break;
1035
1036 case LOOPCASE_CONDITIONAL_CONTINUE:
1037 numIters = iterCount - 1;
1038 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
1039 break;
1040
1041 case LOOPCASE_UNCONDITIONAL_CONTINUE:
1042 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1043 break;
1044
1045 case LOOPCASE_ONLY_CONTINUE:
1046 numIters = 0;
1047 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1048 break;
1049
1050 case LOOPCASE_DOUBLE_CONTINUE:
1051 numIters = iterCount - 1;
1052 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1053 break;
1054
1055 case LOOPCASE_CONDITIONAL_BREAK:
1056 numIters = 2;
1057 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1058 break;
1059
1060 case LOOPCASE_UNCONDITIONAL_BREAK:
1061 numIters = 1;
1062 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
1063 break;
1064
1065 case LOOPCASE_PRE_INCREMENT:
1066 op << " ${COUNTER_PRECISION} int i = 0;\n";
1067 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1068 break;
1069
1070 case LOOPCASE_POST_INCREMENT:
1071 numIters = iterCount + 1;
1072 op << " ${COUNTER_PRECISION} int i = 0;\n";
1073 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
1074 break;
1075
1076 case LOOPCASE_MIXED_BREAK_CONTINUE:
1077 numIters = 2;
1078 iterCount = 5;
1079 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } "
1080 "${DO_WHILE_POST}\n";
1081 break;
1082
1083 case LOOPCASE_VECTOR_COUNTER:
1084 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1085 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1086 break;
1087
1088 case LOOPCASE_101_ITERATIONS:
1089 numIters = iterCount = 101;
1090 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1091 break;
1092
1093 case LOOPCASE_SEQUENCE:
1094 iterCount = 5;
1095 numIters = 5;
1096 op << " ${COUNTER_PRECISION} int i = 0;\n";
1097 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
1098 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1099 break;
1100
1101 case LOOPCASE_NESTED:
1102 numIters = 2 * iterCount;
1103 op << " ${COUNTER_PRECISION} int i = 0;\n";
1104 op << " do\n";
1105 op << " {\n";
1106 op << " ${COUNTER_PRECISION} int j = 0;\n";
1107 op << " do\n";
1108 op << " res = res.yzwx;\n";
1109 op << " while (++j < ${ITER_COUNT});\n";
1110 op << " } while (++i < ${TWO});\n";
1111 break;
1112
1113 case LOOPCASE_NESTED_SEQUENCE:
1114 numIters = 3 * iterCount;
1115 op << " ${COUNTER_PRECISION} int i = 0;\n";
1116 op << " do\n";
1117 op << " {\n";
1118 op << " ${COUNTER_PRECISION} int j = 0;\n";
1119 op << " do\n";
1120 op << " res = res.yzwx;\n";
1121 op << " while (++j < ${TWO});\n";
1122 op << " do\n";
1123 op << " res = res.yzwx;\n";
1124 op << " while (++j < ${THREE});\n";
1125 op << " } while (++i < ${ITER_COUNT});\n";
1126 break;
1127
1128 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1129 numIters = 2;
1130 op << " ${DO_WHILE_PRE}\n";
1131 op << " {\n";
1132 op << " res = coords; // ignore outer loop effect \n";
1133 op << " ${COUNTER_PRECISION} int j = 0;\n";
1134 op << " do\n";
1135 op << " res = res.yzwx;\n";
1136 op << " while (++j < ${TWO});\n";
1137 op << " } ${DO_WHILE_POST}\n";
1138 break;
1139
1140 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1141 numIters = iterCount;
1142 op << " ${DO_WHILE_PRE}\n";
1143 op << " {\n";
1144 op << " res = coords.wxyz;\n";
1145 op << " ${COUNTER_PRECISION} int j = 0;\n";
1146 op << " while (j++ < ${TWO})\n";
1147 op << " res = res.yzwx;\n";
1148 op << " coords = res;\n";
1149 op << " } ${DO_WHILE_POST}\n";
1150 break;
1151
1152 case LOOPCASE_CONDITIONAL_BODY:
1153 numIters = de::min(2, iterCount);
1154 op << " ${DO_WHILE_PRE} if (i < 2) res = res.yzwx; ${DO_WHILE_POST}\n";
1155 break;
1156
1157 case LOOPCASE_FUNCTION_CALL_RETURN:
1158 numIters = iterCount;
1159 op << " ${DO_WHILE_PRE}\n";
1160 op << " {\n";
1161 op << " res = func(res);\n";
1162 op << " } ${DO_WHILE_POST}\n";
1163 break;
1164
1165 case LOOPCASE_FUNCTION_CALL_INOUT:
1166 numIters = iterCount;
1167 op << " ${DO_WHILE_PRE}\n";
1168 op << " {\n";
1169 op << " func(res);\n";
1170 op << " } ${DO_WHILE_POST}\n";
1171 break;
1172
1173 default:
1174 DE_ASSERT(false);
1175 }
1176
1177 doWhileLoopPreStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1178 if (loopCountType == LOOPCOUNT_CONSTANT)
1179 doWhileLoopPostStr = string(" while (++i < ") + de::toString(iterCount) + ");\n";
1180 else if (loopCountType == LOOPCOUNT_UNIFORM)
1181 doWhileLoopPostStr = string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1182 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1183 doWhileLoopPostStr = string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1184 else
1185 DE_ASSERT(false);
1186 }
1187
1188 // Shader footers.
1189 if (isVertexCase)
1190 {
1191 vtx << " v_color = res.rgb;\n";
1192 frag << " gl_FragColor = vec4(v_color.rgb, 1.0);\n";
1193 }
1194 else
1195 {
1196 vtx << " v_coords = a_coords;\n";
1197 frag << " gl_FragColor = vec4(res.rgb, 1.0);\n";
1198
1199 if (loopCountType == LOOPCOUNT_DYNAMIC)
1200 vtx << " v_one = a_one;\n";
1201 }
1202
1203 vtx << "}\n";
1204 frag << "}\n";
1205
1206 // Constants.
1207 string oneStr;
1208 string twoStr;
1209 string threeStr;
1210 string iterCountStr;
1211
1212 if (loopCountType == LOOPCOUNT_CONSTANT)
1213 {
1214 oneStr = "1";
1215 twoStr = "2";
1216 threeStr = "3";
1217 iterCountStr = de::toString(iterCount);
1218 }
1219 else if (loopCountType == LOOPCOUNT_UNIFORM)
1220 {
1221 oneStr = "ui_one";
1222 twoStr = "ui_two";
1223 threeStr = "ui_three";
1224 iterCountStr = getIntUniformName(iterCount);
1225 }
1226 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1227 {
1228 oneStr = "one*ui_one";
1229 twoStr = "one*ui_two";
1230 threeStr = "one*ui_three";
1231 iterCountStr = string("one*") + getIntUniformName(iterCount);
1232 }
1233 else
1234 DE_ASSERT(false);
1235
1236 // Fill in shader templates.
1237 map<string, string> params;
1238 params.insert(pair<string, string>("PRECISION", "mediump"));
1239 params.insert(pair<string, string>("ITER_COUNT", iterCountStr));
1240 params.insert(pair<string, string>("COUNTER_PRECISION", counterPrecisionStr));
1241 params.insert(pair<string, string>("FOR_LOOP", forLoopStr));
1242 params.insert(pair<string, string>("WHILE_LOOP", whileLoopStr));
1243 params.insert(pair<string, string>("DO_WHILE_PRE", doWhileLoopPreStr));
1244 params.insert(pair<string, string>("DO_WHILE_POST", doWhileLoopPostStr));
1245 params.insert(pair<string, string>("ONE", oneStr));
1246 params.insert(pair<string, string>("TWO", twoStr));
1247 params.insert(pair<string, string>("THREE", threeStr));
1248
1249 StringTemplate vertTemplate(vtx.str().c_str());
1250 StringTemplate fragTemplate(frag.str().c_str());
1251 string vertexShaderSource = vertTemplate.specialize(params);
1252 string fragmentShaderSource = fragTemplate.specialize(params);
1253
1254 // Create the case.
1255 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1256 LoopRequirement requirement;
1257
1258 if (loopType == LOOPTYPE_FOR && loopCountType == LOOPCOUNT_CONSTANT)
1259 {
1260 if (loopCase == LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK ||
1261 loopCase == LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST ||
1262 loopCase == LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST ||
1263 loopCase == LOOPCASE_SELECT_ITERATION_COUNT || loopCase == LOOPCASE_VECTOR_COUNTER ||
1264 loopCase == LOOPCASE_SEQUENCE)
1265 requirement = LOOPREQUIREMENT_DYNAMIC;
1266 else
1267 requirement = LOOPREQUIREMENT_STANDARD;
1268 }
1269 else
1270 requirement = LOOPREQUIREMENT_DYNAMIC;
1271
1272 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, requirement,
1273 vertexShaderSource.c_str(), fragmentShaderSource.c_str());
1274 }
1275
1276 // ShaderLoopTests.
1277
ShaderLoopTests(Context & context)1278 ShaderLoopTests::ShaderLoopTests(Context &context) : TestCaseGroup(context, "loops", "Loop Tests")
1279 {
1280 }
1281
~ShaderLoopTests(void)1282 ShaderLoopTests::~ShaderLoopTests(void)
1283 {
1284 }
1285
init(void)1286 void ShaderLoopTests::init(void)
1287 {
1288 // Loop cases.
1289
1290 static const ShaderType s_shaderTypes[] = {SHADERTYPE_VERTEX, SHADERTYPE_FRAGMENT};
1291
1292 static const DataType s_countDataType[] = {TYPE_INT, TYPE_FLOAT};
1293
1294 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1295 {
1296 const char *loopTypeName = getLoopTypeName((LoopType)loopType);
1297
1298 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1299 {
1300 const char *loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1301
1302 string groupName = string(loopTypeName) + "_" + string(loopCountName) + "_iterations";
1303 string groupDesc = string("Loop tests with ") + loopCountName + " loop counter.";
1304 TestCaseGroup *group = new TestCaseGroup(m_context, groupName.c_str(), groupDesc.c_str());
1305 addChild(group);
1306
1307 // Generic cases.
1308
1309 for (int precision = 0; precision < PRECISION_LAST; precision++)
1310 {
1311 const char *precisionName = getPrecisionName((Precision)precision);
1312
1313 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1314 {
1315 DataType loopDataType = s_countDataType[dataTypeNdx];
1316 const char *dataTypeName = getDataTypeName(loopDataType);
1317
1318 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1319 {
1320 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1321 const char *shaderTypeName = getShaderTypeName(shaderType);
1322 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
1323
1324 string name = string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1325 string desc = string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " +
1326 loopCountName + " iteration count in " + shaderTypeName + " shader.";
1327 group->addChild(createGenericLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase,
1328 (LoopType)loopType, (LoopCountType)loopCountType,
1329 (Precision)precision, loopDataType));
1330 }
1331 }
1332 }
1333
1334 // Special cases.
1335
1336 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1337 {
1338 const char *loopCaseName = getLoopCaseName((LoopCase)loopCase);
1339
1340 // no-iterations not possible with do-while.
1341 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1342 continue;
1343
1344 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1345 {
1346 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1347 const char *shaderTypeName = getShaderTypeName(shaderType);
1348 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
1349
1350 string name = string(loopCaseName) + "_" + shaderTypeName;
1351 string desc = string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " +
1352 shaderTypeName + " shader.";
1353 group->addChild(createSpecialLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase,
1354 (LoopCase)loopCase, (LoopType)loopType,
1355 (LoopCountType)loopCountType));
1356 }
1357 }
1358 }
1359 }
1360
1361 // Additional smaller handwritten tests.
1362 const std::vector<tcu::TestNode *> children =
1363 gls::ShaderLibrary(m_context.getTestContext(), m_context.getRenderContext(), m_context.getContextInfo())
1364 .loadShaderFile("shaders/loops.test");
1365 for (int i = 0; i < (int)children.size(); i++)
1366 addChild(children[i]);
1367 }
1368
1369 } // namespace Functional
1370 } // namespace gles2
1371 } // namespace deqp
1372