• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 using namespace std;
37 using namespace tcu;
38 using namespace glu;
39 
40 namespace deqp
41 {
42 
43 // Repeated with for, while, do-while. Examples given as 'for' loops.
44 // Repeated for const, uniform, dynamic loops.
45 enum 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 
getLoopCaseName(LoopCase loopCase)79 static 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 
105 enum LoopType
106 {
107 	LOOPTYPE_FOR = 0,
108 	LOOPTYPE_WHILE,
109 	LOOPTYPE_DO_WHILE,
110 
111 	LOOPTYPE_LAST
112 };
113 
getLoopTypeName(LoopType loopType)114 static 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 
123 enum LoopCountType
124 {
125 	LOOPCOUNT_CONSTANT = 0,
126 	LOOPCOUNT_UNIFORM,
127 	LOOPCOUNT_DYNAMIC,
128 
129 	LOOPCOUNT_LAST
130 };
131 
getLoopCountTypeName(LoopCountType countType)132 static 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 
evalLoop0Iters(ShaderEvalContext & c)141 static void evalLoop0Iters(ShaderEvalContext& c)
142 {
143 	c.color.xyz() = c.coords.swizzle(0, 1, 2);
144 }
evalLoop1Iters(ShaderEvalContext & c)145 static void evalLoop1Iters(ShaderEvalContext& c)
146 {
147 	c.color.xyz() = c.coords.swizzle(1, 2, 3);
148 }
evalLoop2Iters(ShaderEvalContext & c)149 static void evalLoop2Iters(ShaderEvalContext& c)
150 {
151 	c.color.xyz() = c.coords.swizzle(2, 3, 0);
152 }
evalLoop3Iters(ShaderEvalContext & c)153 static void evalLoop3Iters(ShaderEvalContext& c)
154 {
155 	c.color.xyz() = c.coords.swizzle(3, 0, 1);
156 }
157 
getLoopEvalFunc(int numIters)158 static 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 
178 class ShaderLoopCase : public ShaderRenderCase
179 {
180 public:
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 
185 private:
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 
ShaderLoopCase(Context & context,const char * name,const char * description,bool isVertexCase,ShaderEvalFunc evalFunc,const char * vertShaderSource,const char * fragShaderSource)193 ShaderLoopCase::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 
~ShaderLoopCase(void)202 ShaderLoopCase::~ShaderLoopCase(void)
203 {
204 }
205 
setup(deUint32 programID)206 void ShaderLoopCase::setup(deUint32 programID)
207 {
208 	DE_UNREF(programID);
209 }
210 
setupUniforms(deUint32 programID,const Vec4 & constCoords)211 void ShaderLoopCase::setupUniforms(deUint32 programID, const Vec4& constCoords)
212 {
213 	DE_UNREF(programID);
214 	DE_UNREF(constCoords);
215 }
216 
217 // Test case creation.
218 
createGenericLoopCase(Context & context,glu::GLSLVersion glslVersion,const char * caseName,const char * description,bool isVertexCase,LoopType loopType,LoopCountType loopCountType,Precision loopCountPrecision,DataType loopCountDataType)219 static 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?
createSpecialLoopCase(Context & context,glu::GLSLVersion glslVersion,const char * caseName,const char * description,bool isVertexCase,LoopCase loopCase,LoopType loopType,LoopCountType loopCountType)424 static 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 
ShaderLoopTests(Context & context,glu::GLSLVersion glslVersion)1125 ShaderLoopTests::ShaderLoopTests(Context& context, glu::GLSLVersion glslVersion)
1126 	: TestCaseGroup(context, "loops", "Loop Tests"), m_glslVersion(glslVersion)
1127 {
1128 }
1129 
~ShaderLoopTests(void)1130 ShaderLoopTests::~ShaderLoopTests(void)
1131 {
1132 }
1133 
init(void)1134 void 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