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