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