Home | History | Annotate | Download | only in functional
      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 
    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 
    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 
    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 
    188 static void evalLoop0Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(0,1,2); }
    189 static void evalLoop1Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(1,2,3); }
    190 static void evalLoop2Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(2,3,0); }
    191 static void evalLoop3Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(3,0,1); }
    192 
    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 
    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 
    235 ShaderLoopCase::~ShaderLoopCase (void)
    236 {
    237 }
    238 
    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 
    263 void ShaderLoopCase::setup (int programID)
    264 {
    265 	DE_UNREF(programID);
    266 }
    267 
    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 
    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?
    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 
   1255 ShaderLoopTests::ShaderLoopTests(Context& context)
   1256 	: TestCaseGroup(context, "loops", "Loop Tests")
   1257 {
   1258 }
   1259 
   1260 ShaderLoopTests::~ShaderLoopTests (void)
   1261 {
   1262 }
   1263 
   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