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