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