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