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