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