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