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