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
35namespace vkt
36{
37namespace sr
38{
39namespace
40{
41
42static 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
62static 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
80static 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
98static 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
116enum LoopType
117{
118	LOOPTYPE_FOR = 0,
119	LOOPTYPE_WHILE,
120	LOOPTYPE_DO_WHILE,
121	LOOPTYPE_LAST
122};
123
124static 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
138enum 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.
149enum 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
183static 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
221static 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
235static void evalLoop0Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(0,1,2); }
236static void evalLoop1Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(1,2,3); }
237static void evalLoop2Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(2,3,0); }
238static void evalLoop3Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(3,0,1); }
239
240static 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
256class ShaderLoopCase : public ShaderRenderCase
257{
258public:
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
276class LoopUniformSetup : public UniformSetup
277{
278public:
279									LoopUniformSetup	(std::vector<BaseUniformType>& types)
280										: m_uniformInformations(types)
281									{}
282
283	virtual void					setup				(ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
284
285private:
286	std::vector<BaseUniformType>	m_uniformInformations;
287};
288
289void 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
299static 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
522static 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
1252class ShaderLoopTests : public tcu::TestCaseGroup
1253{
1254public:
1255							ShaderLoopTests			(tcu::TestContext& testCtx);
1256	virtual					~ShaderLoopTests		(void);
1257
1258	virtual void			init					(void);
1259
1260private:
1261							ShaderLoopTests			(const ShaderLoopTests&);		// not allowed!
1262	ShaderLoopTests&		operator=				(const ShaderLoopTests&);		// not allowed!
1263};
1264
1265ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1266		: TestCaseGroup(testCtx, "loops", "Loop Tests")
1267{
1268}
1269
1270ShaderLoopTests::~ShaderLoopTests (void)
1271{
1272}
1273
1274void 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
1363tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1364{
1365	return new ShaderLoopTests(testCtx);
1366}
1367
1368
1369} // sr
1370} // vkt
1371