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