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