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