1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Shader loop tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderRenderLoopTests.hpp"
27 
28 #include "vktShaderRender.hpp"
29 #include "tcuStringTemplate.hpp"
30 #include "gluShaderUtil.hpp"
31 #include "deStringUtil.hpp"
32 
33 #include <map>
34 
35 namespace vkt
36 {
37 namespace sr
38 {
39 namespace
40 {
41 
getIntUniformName(int number)42 static const char* getIntUniformName (int number)
43 {
44 	switch (number)
45 	{
46 		case 0:		return "ui_zero";
47 		case 1:		return "ui_one";
48 		case 2:		return "ui_two";
49 		case 3:		return "ui_three";
50 		case 4:		return "ui_four";
51 		case 5:		return "ui_five";
52 		case 6:		return "ui_six";
53 		case 7:		return "ui_seven";
54 		case 8:		return "ui_eight";
55 		case 101:	return "ui_oneHundredOne";
56 		default:
57 			DE_ASSERT(false);
58 			return "";
59 	}
60 }
61 
getIntUniformType(int number)62 static BaseUniformType getIntUniformType(int number)
63 {
64 	switch (number)
65 	{
66 		case 1:		return UI_ONE;
67 		case 2:		return UI_TWO;
68 		case 3:		return UI_THREE;
69 		case 4:		return UI_FOUR;
70 		case 5:		return UI_FIVE;
71 		case 6:		return UI_SIX;
72 		case 7:		return UI_SEVEN;
73 		case 8:		return UI_EIGHT;
74 		default:
75 			DE_ASSERT(false);
76 			return UB_FALSE;
77 	}
78 }
79 
getFloatFractionUniformName(int number)80 static const char* getFloatFractionUniformName (int number)
81 {
82 	switch (number)
83 	{
84 		case 1: return "uf_one";
85 		case 2: return "uf_half";
86 		case 3: return "uf_third";
87 		case 4: return "uf_fourth";
88 		case 5: return "uf_fifth";
89 		case 6: return "uf_sixth";
90 		case 7: return "uf_seventh";
91 		case 8: return "uf_eight";
92 		default:
93 			DE_ASSERT(false);
94 			return "";
95 	}
96 }
97 
getFloatFractionUniformType(int number)98 static BaseUniformType getFloatFractionUniformType(int number)
99 {
100 	switch (number)
101 	{
102 		case 1:		return UF_ONE;
103 		case 2:		return UF_HALF;
104 		case 3:		return UF_THIRD;
105 		case 4:		return UF_FOURTH;
106 		case 5:		return UF_FIFTH;
107 		case 6:		return UF_SIXTH;
108 		case 7:		return UF_SEVENTH;
109 		case 8:		return UF_EIGHTH;
110 		default:
111 			DE_ASSERT(false);
112 			return UB_FALSE;
113 	}
114 }
115 
116 enum LoopType
117 {
118 	LOOPTYPE_FOR = 0,
119 	LOOPTYPE_WHILE,
120 	LOOPTYPE_DO_WHILE,
121 	LOOPTYPE_LAST
122 };
123 
getLoopTypeName(LoopType loopType)124 static const char* getLoopTypeName (LoopType loopType)
125 {
126 	static const char* s_names[] =
127 	{
128 		"for",
129 		"while",
130 		"do_while"
131 	};
132 
133 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
134 	DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
135 	return s_names[(int)loopType];
136 }
137 
138 enum LoopCountType
139 {
140 	LOOPCOUNT_CONSTANT = 0,
141 	LOOPCOUNT_UNIFORM,
142 	LOOPCOUNT_DYNAMIC,
143 
144 	LOOPCOUNT_LAST
145 };
146 
147 // Repeated with for, while, do-while. Examples given as 'for' loops.
148 // Repeated for const, uniform, dynamic loops.
149 enum LoopCase
150 {
151 		LOOPCASE_EMPTY_BODY = 0,							// for (...) { }
152 		LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST,	// for (...) { break; <body>; }
153 		LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST,	// for (...) { <body>; break; }
154 		LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK,			// for (...) { <body>; if (cond) break; }
155 		LOOPCASE_SINGLE_STATEMENT,							// for (...) statement;
156 		LOOPCASE_COMPOUND_STATEMENT,						// for (...) { statement; statement; }
157 		LOOPCASE_SEQUENCE_STATEMENT,						// for (...) statement, statement;
158 		LOOPCASE_NO_ITERATIONS,								// for (i=0; i<0; i++) ...
159 		LOOPCASE_SINGLE_ITERATION,							// for (i=0; i<1; i++) ...
160 		LOOPCASE_SELECT_ITERATION_COUNT,					// for (i=0; i<a?b:c; i++) ...
161 		LOOPCASE_CONDITIONAL_CONTINUE,						// for (...) { if (cond) continue; }
162 		LOOPCASE_UNCONDITIONAL_CONTINUE,					// for (...) { <body>; continue; }
163 		LOOPCASE_ONLY_CONTINUE,								// for (...) { continue; }
164 		LOOPCASE_DOUBLE_CONTINUE,							// for (...) { if (cond) continue; <body>; $
165 		LOOPCASE_CONDITIONAL_BREAK,							// for (...) { if (cond) break; }
166 		LOOPCASE_UNCONDITIONAL_BREAK,						// for (...) { <body>; break; }
167 		LOOPCASE_PRE_INCREMENT,								// for (...; ++i) { <body>; }
168 		LOOPCASE_POST_INCREMENT,							// for (...; i++) { <body>; }
169 		LOOPCASE_MIXED_BREAK_CONTINUE,
170 		LOOPCASE_VECTOR_COUNTER,							// for (ivec3 ndx = ...; ndx.x < ndx.y; ndx$
171 		LOOPCASE_101_ITERATIONS,							// loop for 101 iterations
172 		LOOPCASE_SEQUENCE,									// two loops in sequence
173 		LOOPCASE_NESTED,									// two nested loops
174 		LOOPCASE_NESTED_SEQUENCE,							// two loops in sequence nested inside a th$
175 		LOOPCASE_NESTED_TRICKY_DATAFLOW_1,					// nested loops with tricky data flow
176 		LOOPCASE_NESTED_TRICKY_DATAFLOW_2,					// nested loops with tricky data flow
177 		LOOPCASE_PRE_FALLTHROUGH,							// loop inside switch fallthrough portion
178 		LOOPCASE_POST_FALLTHROUGH,							// loop inside switch with fallthrough after
179 		LOOPCASE_DOWHILE_TRAP,								// dowhile loop inside loop which shouldn't loop
180 		LOOPCASE_IFBLOCK,									// loop inside if block
181 		LOOPCASE_ELSEBLOCK,									// loop inside else block
182 		//LOOPCASE_MULTI_DECLARATION,						// for (int i,j,k; ...) ...  -- illegal?
183 
184 		LOOPCASE_LAST
185 };
186 
getLoopCaseName(LoopCase loopCase)187 static const char* getLoopCaseName (LoopCase loopCase)
188 {
189 		static const char* s_names[] =
190 		{
191 				"empty_body",
192 				"infinite_with_unconditional_break_first",
193 				"infinite_with_unconditional_break_last",
194 				"infinite_with_conditional_break",
195 				"single_statement",
196 				"compound_statement",
197 				"sequence_statement",
198 				"no_iterations",
199 				"single_iteration",
200 				"select_iteration_count",
201 				"conditional_continue",
202 				"unconditional_continue",
203 				"only_continue",
204 				"double_continue",
205 				"conditional_break",
206 				"unconditional_break",
207 				"pre_increment",
208 				"post_increment",
209 				"mixed_break_continue",
210 				"vector_counter",
211 				"101_iterations",
212 				"sequence",
213 				"nested",
214 				"nested_sequence",
215 				"nested_tricky_dataflow_1",
216 				"nested_tricky_dataflow_2",
217 				"pre_fallthrough",
218 				"post_fallthrough",
219 				"dowhile_trap",
220 				"ifblock",
221 				"elseblock"
222 				// "multi_declaration",
223 		};
224 
225 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
226 		DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
227 		return s_names[(int)loopCase];
228 }
229 
getLoopCountTypeName(LoopCountType countType)230 static const char* getLoopCountTypeName (LoopCountType countType)
231 {
232 	static const char* s_names[] =
233 	{
234 		"constant",
235 		"uniform",
236 		"dynamic"
237 	};
238 
239 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
240 	DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
241 	return s_names[(int)countType];
242 }
243 
evalLoop0Iters(ShaderEvalContext & c)244 static void evalLoop0Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(0,1,2); }
evalLoop1Iters(ShaderEvalContext & c)245 static void evalLoop1Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(1,2,3); }
evalLoop2Iters(ShaderEvalContext & c)246 static void evalLoop2Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(2,3,0); }
evalLoop3Iters(ShaderEvalContext & c)247 static void evalLoop3Iters	(ShaderEvalContext& c) { c.color.xyz()	= c.coords.swizzle(3,0,1); }
248 
getLoopEvalFunc(int numIters)249 static ShaderEvalFunc getLoopEvalFunc (int numIters)
250 {
251 	switch (numIters % 4)
252 	{
253 		case 0: return evalLoop0Iters;
254 		case 1:	return evalLoop1Iters;
255 		case 2:	return evalLoop2Iters;
256 		case 3:	return evalLoop3Iters;
257 	}
258 
259 	DE_FATAL("Invalid loop iteration count.");
260 	return NULL;
261 }
262 
263 // ShaderLoop case
264 
265 class ShaderLoopCase : public ShaderRenderCase
266 {
267 public:
ShaderLoopCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,bool isVertexCase,ShaderEvalFunc evalFunc,UniformSetup * uniformSetup,const std::string & vertexShaderSource,const std::string & fragmentShaderSource)268 	ShaderLoopCase	(tcu::TestContext&	testCtx,
269 					 const std::string&	name,
270 					 const std::string&	description,
271 					 bool				isVertexCase,
272 					 ShaderEvalFunc		evalFunc,
273 					 UniformSetup*		uniformSetup,
274 					 const std::string&	vertexShaderSource,
275 					 const std::string&	fragmentShaderSource)
276 		: ShaderRenderCase		(testCtx, name, description, isVertexCase, evalFunc, uniformSetup, DE_NULL)
277 	{
278 		m_vertShaderSource = vertexShaderSource;
279 		m_fragShaderSource = fragmentShaderSource;
280 	}
281 };
282 
283 // Uniform setup tools
284 
285 class LoopUniformSetup : public UniformSetup
286 {
287 public:
LoopUniformSetup(std::vector<BaseUniformType> & types)288 									LoopUniformSetup	(std::vector<BaseUniformType>& types)
289 										: m_uniformInformations(types)
290 									{}
291 
292 	virtual void					setup				(ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
293 
294 private:
295 	std::vector<BaseUniformType>	m_uniformInformations;
296 };
297 
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 &) const298 void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
299 {
300 	for (size_t i = 0; i < m_uniformInformations.size(); i++)
301 	{
302 		instance.useUniform((deUint32)i, m_uniformInformations[i]);
303 	}
304 }
305 
306 // Testcase builders
307 
createGenericLoopCase(tcu::TestContext & testCtx,const std::string & caseName,const std::string & description,bool isVertexCase,LoopType loopType,LoopCountType loopCountType,glu::Precision loopCountPrecision,glu::DataType loopCountDataType)308 static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext&	testCtx,
309 														const std::string&	caseName,
310 														const std::string&	description,
311 														bool				isVertexCase,
312 														LoopType			loopType,
313 														LoopCountType		loopCountType,
314 														glu::Precision		loopCountPrecision,
315 														glu::DataType		loopCountDataType)
316 {
317 	std::ostringstream vtx;
318 	std::ostringstream frag;
319 	std::ostringstream& op = isVertexCase ? vtx : frag;
320 
321 	vtx << "#version 310 es\n";
322 	frag << "#version 310 es\n";
323 
324 	vtx << "layout(location=0) in highp vec4 a_position;\n";
325 	vtx << "layout(location=1) in highp vec4 a_coords;\n";
326 	frag << "layout(location=0) out mediump vec4 o_color;\n";
327 
328 	if (loopCountType == LOOPCOUNT_DYNAMIC)
329 		vtx << "layout(location=3) in mediump float a_one;\n";
330 
331 	if (isVertexCase)
332 	{
333 		vtx << "layout(location=0) out mediump vec3 v_color;\n";
334 		frag << "layout(location=0) in mediump vec3 v_color;\n";
335 	}
336 	else
337 	{
338 		vtx << "layout(location=0) out mediump vec4 v_coords;\n";
339 		frag << "layout(location=0) in mediump vec4 v_coords;\n";
340 
341 		if (loopCountType == LOOPCOUNT_DYNAMIC)
342 		{
343 			vtx << "layout(location=1) out mediump float v_one;\n";
344 			frag << "layout(location=1) in mediump float v_one;\n";
345 		}
346 	}
347 
348 	const int	numLoopIters = 3;
349 	const bool	isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
350 	deUint32	locationCounter = 0;
351 	std::vector<BaseUniformType> uniformInformations;
352 
353 	if (isIntCounter)
354 	{
355 		if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
356 		{
357 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
358 			op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
359 			op << "};\n";
360 			uniformInformations.push_back(getIntUniformType(numLoopIters));
361 			locationCounter++;
362 		}
363 	}
364 	else
365 	{
366 		if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
367 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
368 			op << "	${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
369 			op << "};\n";
370 			uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
371 			locationCounter++;
372 		}
373 
374 		if (numLoopIters != 1){
375 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
376 			op << "	${COUNTER_PRECISION} float uf_one;\n";
377 			op << "};\n";
378 			uniformInformations.push_back(UF_ONE);
379 			locationCounter++;
380 		}
381 	}
382 
383 	vtx << "\n";
384 	vtx << "void main()\n";
385 	vtx << "{\n";
386 	vtx << "	gl_Position = a_position;\n";
387 
388 	frag << "\n";
389 	frag << "void main()\n";
390 	frag << "{\n";
391 
392 	if (isVertexCase)
393 		vtx << "	${PRECISION} vec4 coords = a_coords;\n";
394 	else
395 		frag << "	${PRECISION} vec4 coords = v_coords;\n";
396 
397 
398 	if (loopCountType == LOOPCOUNT_DYNAMIC)
399 	{
400 		if (isIntCounter)
401 		{
402 			if (isVertexCase)
403 				vtx << "	${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
404 			else
405 				frag << "	${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
406 		}
407 		else
408 		{
409 			if (isVertexCase)
410 				vtx << "	${COUNTER_PRECISION} float one = a_one;\n";
411 			else
412 				frag << "	${COUNTER_PRECISION} float one = v_one;\n";
413 		}
414 	}
415 
416 	// Read array.
417 	op << "	${PRECISION} vec4 res = coords;\n";
418 
419 	// Loop iteration count.
420 	std::string	iterMaxStr;
421 
422 	if (isIntCounter)
423 	{
424 		if (loopCountType == LOOPCOUNT_CONSTANT)
425 			iterMaxStr = de::toString(numLoopIters);
426 		else if (loopCountType == LOOPCOUNT_UNIFORM)
427 			iterMaxStr = getIntUniformName(numLoopIters);
428 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
429 			iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
430 		else
431 			DE_ASSERT(false);
432 	}
433 	else
434 	{
435 		if (loopCountType == LOOPCOUNT_CONSTANT)
436 			iterMaxStr = "1.0";
437 		else if (loopCountType == LOOPCOUNT_UNIFORM)
438 			iterMaxStr = "uf_one";
439 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
440 			iterMaxStr = "uf_one*one";
441 		else
442 			DE_ASSERT(false);
443 	}
444 
445 	// Loop operations.
446 	std::string initValue			= isIntCounter ? "0" : "0.05";
447 	std::string loopCountDeclStr	= "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
448 	std::string loopCmpStr			= ("ndx < " + iterMaxStr);
449 	std::string incrementStr;
450 	if (isIntCounter)
451 		incrementStr = "ndx++";
452 	else
453 	{
454 		if (loopCountType == LOOPCOUNT_CONSTANT)
455 			incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
456 		else if (loopCountType == LOOPCOUNT_UNIFORM)
457 			incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
458 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
459 			incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
460 		else
461 			DE_ASSERT(false);
462 	}
463 
464 	// Loop body.
465 	std::string loopBody;
466 
467 	loopBody = "		res = res.yzwx + vec4(1.0);\n";
468 
469 	if (loopType == LOOPTYPE_FOR)
470 	{
471 		op << "	for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
472 		op << "	{\n";
473 		op << loopBody;
474 		op << "	}\n";
475 	}
476 	else if (loopType == LOOPTYPE_WHILE)
477 	{
478 		op << "\t" << loopCountDeclStr + ";\n";
479 		op << "	while (" + loopCmpStr + ")\n";
480 		op << "	{\n";
481 		op << loopBody;
482 		op << "\t\t" + incrementStr + ";\n";
483 		op << "	}\n";
484 	}
485 	else if (loopType == LOOPTYPE_DO_WHILE)
486 	{
487 		op << "\t" << loopCountDeclStr + ";\n";
488 		op << "	do\n";
489 		op << "	{\n";
490 		op << loopBody;
491 		op << "\t\t" + incrementStr + ";\n";
492 		op << "	} while (" + loopCmpStr + ");\n";
493 	}
494 	else
495 		DE_ASSERT(false);
496 
497 	op << "	res -= vec4(" + de::toString(numLoopIters) + ");\n";
498 
499 	if (isVertexCase)
500 	{
501 		vtx << "	v_color = res.rgb;\n";
502 		frag << "	o_color = vec4(v_color.rgb, 1.0);\n";
503 	}
504 	else
505 	{
506 		vtx << "	v_coords = a_coords;\n";
507 		frag << "	o_color = vec4(res.rgb, 1.0);\n";
508 
509 		if (loopCountType == LOOPCOUNT_DYNAMIC)
510 			vtx << "	v_one = a_one;\n";
511 	}
512 
513 	vtx << "}\n";
514 	frag << "}\n";
515 
516 	// Fill in shader templates.
517 	std::map<std::string, std::string> params;
518 	params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
519 	params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
520 	params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
521 
522 	tcu::StringTemplate vertTemplate(vtx.str());
523 	tcu::StringTemplate fragTemplate(frag.str());
524 	std::string vertexShaderSource = vertTemplate.specialize(params);
525 	std::string fragmentShaderSource = fragTemplate.specialize(params);
526 
527 	// Create the case.
528 	ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
529 	UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
530 	return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
531 }
532 
createSpecialLoopCase(tcu::TestContext & testCtx,const std::string & caseName,const std::string & description,bool isVertexCase,LoopCase loopCase,LoopType loopType,LoopCountType loopCountType)533 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext&	testCtx,
534 														const std::string&	caseName,
535 														const std::string&	description,
536 														bool				isVertexCase,
537 														LoopCase			loopCase,
538 														LoopType			loopType,
539 														LoopCountType		loopCountType)
540 {
541 	std::ostringstream vtx;
542 	std::ostringstream frag;
543 	std::ostringstream& op = isVertexCase ? vtx : frag;
544 
545 	std::vector<BaseUniformType>	uniformInformations;
546 	deUint32						locationCounter = 0;
547 
548 	vtx << "#version 310 es\n";
549 	frag << "#version 310 es\n";
550 
551 	vtx << "layout(location=0) in highp vec4 a_position;\n";
552 	vtx << "layout(location=1) in highp vec4 a_coords;\n";
553 	frag << "layout(location=0) out mediump vec4 o_color;\n";
554 
555 	if (loopCountType == LOOPCOUNT_DYNAMIC)
556 		vtx << "layout(location=3) in mediump float a_one;\n";
557 
558 	if (isVertexCase)
559 	{
560 		vtx << "layout(location=0) out mediump vec3 v_color;\n";
561 		frag << "layout(location=0) in mediump vec3 v_color;\n";
562 	}
563 	else
564 	{
565 		vtx << "layout(location=0) out mediump vec4 v_coords;\n";
566 		frag << "layout(location=0) in mediump vec4 v_coords;\n";
567 
568 		if (loopCountType == LOOPCOUNT_DYNAMIC)
569 		{
570 			vtx << "layout(location=1) out mediump float v_one;\n";
571 			frag << "layout(location=1) in mediump float v_one;\n";
572 		}
573 	}
574 
575 	if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
576 		op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
577 		op << "  bool ub_true;\n";
578 		op << "};\n";
579 		uniformInformations.push_back(UB_TRUE);
580 		locationCounter++;
581 	}
582 
583 	struct
584 	{
585 		char const*		name;
586 		BaseUniformType	type;
587 	} uniforms[] =
588 	{
589 		{ "ui_zero",	UI_ZERO },
590 		{ "ui_one",		UI_ONE },
591 		{ "ui_two",		UI_TWO },
592 		{ "ui_three",	UI_THREE },
593 		{ "ui_four",	UI_FOUR },
594 		{ "ui_five",	UI_FIVE },
595 		{ "ui_six",		UI_SIX  },
596 	};
597 
598 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
599 	{
600 		op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
601 		op << "  ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
602 		op << "};\n";
603 		uniformInformations.push_back(uniforms[i].type);
604 		locationCounter++;
605 	}
606 
607 	if (loopCase == LOOPCASE_101_ITERATIONS) {
608 
609 		op << "layout(std140, set=0, binding=" << locationCounter <<  ") uniform buff" << locationCounter << " {\n";
610 		op << "  ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
611 		op << "};\n";
612 		uniformInformations.push_back(UI_ONEHUNDREDONE);
613 		locationCounter++;
614 	}
615 
616 	int iterCount	= 3;	// value to use in loop
617 	int numIters	= 3;	// actual number of iterations
618 
619 	vtx << "\n";
620 	vtx << "void main()\n";
621 	vtx << "{\n";
622 	vtx << "	gl_Position = a_position;\n";
623 
624 	frag << "\n";
625 	frag << "void main()\n";
626 	frag << "{\n";
627 
628 	if (loopCountType == LOOPCOUNT_DYNAMIC)
629 	{
630 		if (isVertexCase)
631 			vtx << "	${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
632 		else
633 			frag << "	${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
634 	}
635 
636 	if (isVertexCase)
637 		vtx << "	${PRECISION} vec4 coords = a_coords;\n";
638 	else
639 		frag << "	${PRECISION} vec4 coords = v_coords;\n";
640 
641 	// Read array.
642 	op << "	${PRECISION} vec4 res = coords;\n";
643 
644 	// Handle all loop types.
645 	std::string counterPrecisionStr = "mediump";
646 	std::string forLoopStr;
647 	std::string whileLoopStr;
648 	std::string doWhileLoopPreStr;
649 	std::string doWhileLoopPostStr;
650 
651 	if (loopType == LOOPTYPE_FOR)
652 	{
653 		switch (loopCase)
654 		{
655 			case LOOPCASE_EMPTY_BODY:
656 				numIters = 0;
657 				op << "	${FOR_LOOP} {}\n";
658 				break;
659 
660 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
661 				numIters = 0;
662 				op << "	for (;;) { break; res = res.yzwx + vec4(1.0); }\n";
663 				break;
664 
665 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
666 				numIters = 1;
667 				op << "	for (;;) { res = res.yzwx + vec4(1.0); break; }\n";
668 				break;
669 
670 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
671 				numIters = 2;
672 				op << "	${COUNTER_PRECISION} int i = 0;\n";
673 				op << "	for (;;) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
674 				break;
675 
676 			case LOOPCASE_SINGLE_STATEMENT:
677 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
678 				break;
679 
680 			case LOOPCASE_COMPOUND_STATEMENT:
681 				iterCount	= 2;
682 				numIters	= 2 * iterCount;
683 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
684 				break;
685 
686 			case LOOPCASE_SEQUENCE_STATEMENT:
687 				iterCount	= 2;
688 				numIters	= 2 * iterCount;
689 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
690 				break;
691 
692 			case LOOPCASE_NO_ITERATIONS:
693 				iterCount	= 0;
694 				numIters	= 0;
695 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
696 				break;
697 
698 			case LOOPCASE_SINGLE_ITERATION:
699 				iterCount	= 1;
700 				numIters	= 1;
701 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
702 				break;
703 
704 			case LOOPCASE_SELECT_ITERATION_COUNT:
705 				op << "	for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx + vec4(1.0);\n";
706 				break;
707 
708 			case LOOPCASE_CONDITIONAL_CONTINUE:
709 				numIters = iterCount - 1;
710 				op << "	${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
711 				break;
712 
713 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
714 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
715 				break;
716 
717 			case LOOPCASE_ONLY_CONTINUE:
718 				numIters = 0;
719 				op << "	${FOR_LOOP} { continue; }\n";
720 				break;
721 
722 			case LOOPCASE_DOUBLE_CONTINUE:
723 				numIters = iterCount - 1;
724 				op << "	${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
725 				break;
726 
727 			case LOOPCASE_CONDITIONAL_BREAK:
728 				numIters = 2;
729 				op << "	${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx + vec4(1.0); }\n";
730 				break;
731 
732 			case LOOPCASE_UNCONDITIONAL_BREAK:
733 				numIters = 1;
734 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
735 				break;
736 
737 			case LOOPCASE_PRE_INCREMENT:
738 				op << "	for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx + vec4(1.0); }\n";
739 				break;
740 
741 			case LOOPCASE_POST_INCREMENT:
742 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); }\n";
743 				break;
744 
745 			case LOOPCASE_MIXED_BREAK_CONTINUE:
746 				numIters	= 2;
747 				iterCount	= 5;
748 				op << "	${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
749 				break;
750 
751 			case LOOPCASE_VECTOR_COUNTER:
752 				op << "	for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx + vec4(1.0); }\n";
753 				break;
754 
755 			case LOOPCASE_101_ITERATIONS:
756 				numIters = iterCount = 101;
757 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
758 				break;
759 
760 			case LOOPCASE_SEQUENCE:
761 				iterCount	= 5;
762 				numIters	= 5;
763 				op << "	${COUNTER_PRECISION} int i;\n";
764 				op << "	for (i = 0; i < ${TWO}; i++) { res = res.yzwx + vec4(1.0); }\n";
765 				op << "	for (; i < ${ITER_COUNT}; i++) { res = res.yzwx + vec4(1.0); }\n";
766 				break;
767 
768 			case LOOPCASE_NESTED:
769 				numIters = 2 * iterCount;
770 				op << "	for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
771 				op << "	{\n";
772 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
773 				op << "			res = res.yzwx + vec4(1.0);\n";
774 				op << "	}\n";
775 				break;
776 
777 			case LOOPCASE_NESTED_SEQUENCE:
778 				numIters = 3 * iterCount;
779 				op << "	for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
780 				op << "	{\n";
781 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
782 				op << "			res = res.yzwx + vec4(1.0);\n";
783 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
784 				op << "			res = res.yzwx + vec4(1.0);\n";
785 				op << "	}\n";
786 				break;
787 
788 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
789 				numIters = 2;
790 				op << "	${FOR_LOOP}\n";
791 				op << "	{\n";
792 				op << "		res = coords; // ignore outer loop effect \n";
793 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
794 				op << "			res = res.yzwx + vec4(1.0);\n";
795 				op << "	}\n";
796 				break;
797 
798 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
799 				numIters = iterCount;
800 				op << "	${FOR_LOOP}\n";
801 				op << "	{\n";
802 				op << "		res = coords.wxyz - vec4(1.0);\n";
803 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
804 				op << "			res = res.yzwx + vec4(1.0);\n";
805 				op << "		coords = res;\n";
806 				op << "	}\n";
807 				break;
808 
809 			case LOOPCASE_PRE_FALLTHROUGH:
810 				numIters = iterCount + 1;
811 				op << "	int j = 3;\n";
812 				op << "	switch (j)\n";
813 				op << "	{\n";
814 				op << "	case 3:\n";
815 				op << "		res = res.yzwx + vec4(1.0);\n";
816 				op << "	case 4:\n";
817 				op << "		${FOR_LOOP}\n";
818 				op << "			res = res.yzwx + vec4(1.0);\n";
819 				op << "		break;\n";
820 				op << "	}\n";
821 				break;
822 
823 			case LOOPCASE_POST_FALLTHROUGH:
824 				numIters = iterCount + 1;
825 				op << "	int j = 3;\n";
826 				op << "	switch (j)\n";
827 				op << "	{\n";
828 				op << "	case 3:\n";
829 				op << "		${FOR_LOOP}\n";
830 				op << "			res = res.yzwx + vec4(1.0);\n";
831 				op << "	case 4:\n";
832 				op << "		res = res.yzwx + vec4(1.0);\n";
833 				op << "		break;\n";
834 				op << "	}\n";
835 				break;
836 
837 			case LOOPCASE_DOWHILE_TRAP:
838 				numIters = iterCount = 3;
839 				op << "	${FOR_LOOP}\n";
840 				op << "	{\n";
841 				op << "		do\n";
842 				op << "		{\n";
843 				op << "			res = res.yzwx + vec4(1.0);\n";
844 				op << "		} while (i >= ${THREE});\n";
845 				op << "	}\n";
846 				break;
847 
848 			case LOOPCASE_IFBLOCK:
849 				numIters = iterCount;
850 				op << "	int j = 3;\n";
851 				op << "	if (j == ${THREE})\n";
852 				op << "	{\n";
853 				op << "		${FOR_LOOP}\n";
854 				op << "			res = res.yzwx + vec4(1.0);\n";
855 				op << "	}\n";
856 				op << "	else\n";
857 				op << "	{\n";
858 				op << "		res = res.yzwx + vec4(1.0);\n";
859 				op << "	}\n";
860 				break;
861 
862 			case LOOPCASE_ELSEBLOCK:
863 				numIters = iterCount;
864 				op << "	int j = 2;\n";
865 				op << "	if (j == ${THREE})\n";
866 				op << "	{\n";
867 				op << "		res = res.yzwx + vec4(1.0);\n";
868 				op << "	}\n";
869 				op << "	else\n";
870 				op << "	{\n";
871 				op << "		${FOR_LOOP}\n";
872 				op << "			res = res.yzwx + vec4(1.0);\n";
873 				op << "	}\n";
874 				break;
875 
876 			default:
877 				DE_ASSERT(false);
878 		}
879 
880 		if (loopCountType == LOOPCOUNT_CONSTANT)
881 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
882 		else if (loopCountType == LOOPCOUNT_UNIFORM)
883 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
884 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
885 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
886 		else
887 			DE_ASSERT(false);
888 	}
889 	else if (loopType == LOOPTYPE_WHILE)
890 	{
891 		switch (loopCase)
892 		{
893 			case LOOPCASE_EMPTY_BODY:
894 				numIters = 0;
895 				op << "	${WHILE_LOOP} {}\n";
896 				break;
897 
898 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
899 				numIters = 0;
900 				op << "	while (true) { break; res = res.yzwx + vec4(1.0); }\n";
901 				break;
902 
903 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
904 				numIters = 1;
905 				op << "	while (true) { res = res.yzwx + vec4(1.0); break; }\n";
906 				break;
907 
908 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
909 				numIters = 2;
910 				op << "	${COUNTER_PRECISION} int i = 0;\n";
911 				op << "	while (true) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
912 				break;
913 
914 			case LOOPCASE_SINGLE_STATEMENT:
915 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
916 				break;
917 
918 			case LOOPCASE_COMPOUND_STATEMENT:
919 				iterCount	= 2;
920 				numIters	= 2 * iterCount;
921 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
922 				break;
923 
924 			case LOOPCASE_SEQUENCE_STATEMENT:
925 				iterCount	= 2;
926 				numIters	= 2 * iterCount;
927 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
928 				break;
929 
930 			case LOOPCASE_NO_ITERATIONS:
931 				iterCount	= 0;
932 				numIters	= 0;
933 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
934 				break;
935 
936 			case LOOPCASE_SINGLE_ITERATION:
937 				iterCount	= 1;
938 				numIters	= 1;
939 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
940 				break;
941 
942 			case LOOPCASE_SELECT_ITERATION_COUNT:
943 				op << "	${COUNTER_PRECISION} int i = 0;\n";
944 				op << "	while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx + vec4(1.0); i++; }\n";
945 				break;
946 
947 			case LOOPCASE_CONDITIONAL_CONTINUE:
948 				numIters = iterCount - 1;
949 				op << "	${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
950 				break;
951 
952 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
953 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
954 				break;
955 
956 			case LOOPCASE_ONLY_CONTINUE:
957 				numIters = 0;
958 				op << "	${WHILE_LOOP} { continue; }\n";
959 				break;
960 
961 			case LOOPCASE_DOUBLE_CONTINUE:
962 				numIters = iterCount - 1;
963 				op << "	${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
964 				break;
965 
966 			case LOOPCASE_CONDITIONAL_BREAK:
967 				numIters = 2;
968 				op << "	${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx + vec4(1.0); }\n";
969 				break;
970 
971 			case LOOPCASE_UNCONDITIONAL_BREAK:
972 				numIters = 1;
973 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
974 				break;
975 
976 			case LOOPCASE_PRE_INCREMENT:
977 				numIters = iterCount - 1;
978 				op << "	${COUNTER_PRECISION} int i = 0;\n";
979 				op << "	while (++i < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
980 				break;
981 
982 			case LOOPCASE_POST_INCREMENT:
983 				op << "	${COUNTER_PRECISION} int i = 0;\n";
984 				op << "	while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
985 				break;
986 
987 			case LOOPCASE_MIXED_BREAK_CONTINUE:
988 				numIters	= 2;
989 				iterCount	= 5;
990 				op << "	${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
991 				break;
992 
993 			case LOOPCASE_VECTOR_COUNTER:
994 				op << "	${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
995 				op << "	while (i.x < i.z) { res = res.yzwx + vec4(1.0); i.x += i.y; }\n";
996 				break;
997 
998 			case LOOPCASE_101_ITERATIONS:
999 				numIters = iterCount = 101;
1000 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
1001 				break;
1002 
1003 			case LOOPCASE_SEQUENCE:
1004 				iterCount	= 6;
1005 				numIters	= iterCount - 1;
1006 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1007 				op << "	while (i++ < ${TWO}) { res = res.yzwx + vec4(1.0); }\n";
1008 				op << "	while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n"; // \note skips one iteration
1009 				break;
1010 
1011 			case LOOPCASE_NESTED:
1012 				numIters = 2 * iterCount;
1013 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1014 				op << "	while (i++ < ${TWO})\n";
1015 				op << "	{\n";
1016 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1017 				op << "		while (j++ < ${ITER_COUNT})\n";
1018 				op << "			res = res.yzwx + vec4(1.0);\n";
1019 				op << "	}\n";
1020 				break;
1021 
1022 			case LOOPCASE_NESTED_SEQUENCE:
1023 				numIters = 2 * iterCount;
1024 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1025 				op << "	while (i++ < ${ITER_COUNT})\n";
1026 				op << "	{\n";
1027 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1028 				op << "		while (j++ < ${ONE})\n";
1029 				op << "			res = res.yzwx + vec4(1.0);\n";
1030 				op << "		while (j++ < ${THREE})\n"; // \note skips one iteration
1031 				op << "			res = res.yzwx + vec4(1.0);\n";
1032 				op << "	}\n";
1033 				break;
1034 
1035 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1036 				numIters = 2;
1037 				op << "	${WHILE_LOOP}\n";
1038 				op << "	{\n";
1039 				op << "		res = coords; // ignore outer loop effect \n";
1040 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1041 				op << "		while (j++ < ${TWO})\n";
1042 				op << "			res = res.yzwx + vec4(1.0);\n";
1043 				op << "	}\n";
1044 				break;
1045 
1046 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1047 				numIters = iterCount;
1048 				op << "	${WHILE_LOOP}\n";
1049 				op << "	{\n";
1050 				op << "		res = coords.wxyz - vec4(1.0);\n";
1051 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1052 				op << "		while (j++ < ${TWO})\n";
1053 				op << "			res = res.yzwx + vec4(1.0);\n";
1054 				op << "		coords = res;\n";
1055 				op << "	}\n";
1056 				break;
1057 
1058 			case LOOPCASE_PRE_FALLTHROUGH:
1059 				numIters = iterCount + 1;
1060 				op << "	int j = 3;\n";
1061 				op << "	switch (j)\n";
1062 				op << "	{\n";
1063 				op << "	case 3:\n";
1064 				op << "		res = res.yzwx + vec4(1.0);\n";
1065 				op << "	case 4:\n";
1066 				op << "		${WHILE_LOOP}\n";
1067 				op << "			res = res.yzwx + vec4(1.0);\n";
1068 				op << "		break;\n";
1069 				op << "	}\n";
1070 				break;
1071 
1072 			case LOOPCASE_POST_FALLTHROUGH:
1073 				numIters = iterCount + 1;
1074 				op << "	int j = 3;\n";
1075 				op << "	switch (j)\n";
1076 				op << "	{\n";
1077 				op << "	case 3:\n";
1078 				op << "		${WHILE_LOOP}\n";
1079 				op << "			res = res.yzwx + vec4(1.0);\n";
1080 				op << "	case 4:\n";
1081 				op << "		res = res.yzwx + vec4(1.0);\n";
1082 				op << "		break;\n";
1083 				op << "	}\n";
1084 				break;
1085 
1086 			case LOOPCASE_DOWHILE_TRAP:
1087 				numIters = iterCount = 3;
1088 				op << "	${WHILE_LOOP}\n";
1089 				op << "	{\n";
1090 				op << "		do\n";
1091 				op << "		{\n";
1092 				op << "			res = res.yzwx + vec4(1.0);\n";
1093 				op << "		} while (i > ${THREE});\n";
1094 				op << "	}\n";
1095 				break;
1096 
1097 			case LOOPCASE_IFBLOCK:
1098 				numIters = iterCount;
1099 				op << "	int j = 3;\n";
1100 				op << "	if (j == ${THREE})\n";
1101 				op << "	{\n";
1102 				op << "		${WHILE_LOOP}\n";
1103 				op << "			res = res.yzwx + vec4(1.0);\n";
1104 				op << "	}\n";
1105 				op << "	else\n";
1106 				op << "	{\n";
1107 				op << "		res = res.yzwx + vec4(1.0);\n";
1108 				op << "	}\n";
1109 				break;
1110 
1111 			case LOOPCASE_ELSEBLOCK:
1112 				numIters = iterCount;
1113 				op << "	int j = 2;\n";
1114 				op << "	if (j == ${THREE})\n";
1115 				op << "	{\n";
1116 				op << "		res = res.yzwx + vec4(1.0);\n";
1117 				op << "	}\n";
1118 				op << "	else\n";
1119 				op << "	{\n";
1120 				op << "		${WHILE_LOOP}\n";
1121 				op << "			res = res.yzwx + vec4(1.0);\n";
1122 				op << "	}\n";
1123 				break;
1124 
1125 			default:
1126 				DE_ASSERT(false);
1127 		}
1128 
1129 		if (loopCountType == LOOPCOUNT_CONSTANT)
1130 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < " + de::toString(iterCount) + ")";
1131 		else if (loopCountType == LOOPCOUNT_UNIFORM)
1132 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < " + getIntUniformName(iterCount) + ")";
1133 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
1134 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < one*" + getIntUniformName(iterCount) + ")";
1135 		else
1136 			DE_ASSERT(false);
1137 	}
1138 	else
1139 	{
1140 		DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
1141 
1142 		switch (loopCase)
1143 		{
1144 			case LOOPCASE_EMPTY_BODY:
1145 				numIters = 0;
1146 				op << "	${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1147 				break;
1148 
1149 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1150 				numIters = 0;
1151 				op << "	do { break; res = res.yzwx + vec4(1.0); } while (true);\n";
1152 				break;
1153 
1154 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1155 				numIters = 1;
1156 				op << "	do { res = res.yzwx + vec4(1.0); break; } while (true);\n";
1157 				break;
1158 
1159 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1160 				numIters = 2;
1161 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1162 				op << "	do { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; } while (true);\n";
1163 				break;
1164 
1165 			case LOOPCASE_SINGLE_STATEMENT:
1166 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1167 				break;
1168 
1169 			case LOOPCASE_COMPOUND_STATEMENT:
1170 				iterCount	= 2;
1171 				numIters	= 2 * iterCount;
1172 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1173 				break;
1174 
1175 			case LOOPCASE_SEQUENCE_STATEMENT:
1176 				iterCount	= 2;
1177 				numIters	= 2 * iterCount;
1178 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1179 				break;
1180 
1181 			case LOOPCASE_NO_ITERATIONS:
1182 				DE_ASSERT(false);
1183 				break;
1184 
1185 			case LOOPCASE_SINGLE_ITERATION:
1186 				iterCount	= 1;
1187 				numIters	= 1;
1188 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1189 				break;
1190 
1191 			case LOOPCASE_SELECT_ITERATION_COUNT:
1192 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1193 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1194 				break;
1195 
1196 			case LOOPCASE_CONDITIONAL_CONTINUE:
1197 				numIters = iterCount - 1;
1198 				op << "	${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1199 				break;
1200 
1201 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
1202 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
1203 				break;
1204 
1205 			case LOOPCASE_ONLY_CONTINUE:
1206 				numIters = 0;
1207 				op << "	${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1208 				break;
1209 
1210 			case LOOPCASE_DOUBLE_CONTINUE:
1211 				numIters = iterCount - 1;
1212 				op << "	${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
1213 				break;
1214 
1215 			case LOOPCASE_CONDITIONAL_BREAK:
1216 				numIters = 2;
1217 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1218 				break;
1219 
1220 			case LOOPCASE_UNCONDITIONAL_BREAK:
1221 				numIters = 1;
1222 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); break; } ${DO_WHILE_POST}\n";
1223 				break;
1224 
1225 			case LOOPCASE_PRE_INCREMENT:
1226 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1227 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
1228 				break;
1229 
1230 			case LOOPCASE_POST_INCREMENT:
1231 				numIters = iterCount + 1;
1232 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1233 				op << "	do { res = res.yzwx + vec4(1.0); } while (i++ < ${ITER_COUNT});\n";
1234 				break;
1235 
1236 			case LOOPCASE_MIXED_BREAK_CONTINUE:
1237 				numIters	= 2;
1238 				iterCount	= 5;
1239 				op << "	${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1240 				break;
1241 
1242 			case LOOPCASE_VECTOR_COUNTER:
1243 				op << "	${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1244 				op << "	do { res = res.yzwx + vec4(1.0); } while ((i.x += i.y) < i.z);\n";
1245 				break;
1246 
1247 			case LOOPCASE_101_ITERATIONS:
1248 				numIters = iterCount = 101;
1249 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1250 				break;
1251 
1252 			case LOOPCASE_SEQUENCE:
1253 				iterCount	= 5;
1254 				numIters	= 5;
1255 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1256 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${TWO});\n";
1257 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
1258 				break;
1259 
1260 			case LOOPCASE_NESTED:
1261 				numIters = 2 * iterCount;
1262 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1263 				op << "	do\n";
1264 				op << "	{\n";
1265 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1266 				op << "		do\n";
1267 				op << "			res = res.yzwx + vec4(1.0);\n";
1268 				op << "		while (++j < ${ITER_COUNT});\n";
1269 				op << "	} while (++i < ${TWO});\n";
1270 				break;
1271 
1272 			case LOOPCASE_NESTED_SEQUENCE:
1273 				numIters = 3 * iterCount;
1274 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1275 				op << "	do\n";
1276 				op << "	{\n";
1277 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1278 				op << "		do\n";
1279 				op << "			res = res.yzwx + vec4(1.0);\n";
1280 				op << "		while (++j < ${TWO});\n";
1281 				op << "		do\n";
1282 				op << "			res = res.yzwx + vec4(1.0);\n";
1283 				op << "		while (++j < ${THREE});\n";
1284 				op << "	} while (++i < ${ITER_COUNT});\n";
1285 				break;
1286 
1287 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1288 				numIters = 2;
1289 				op << "	${DO_WHILE_PRE}\n";
1290 				op << "	{\n";
1291 				op << "		res = coords; // ignore outer loop effect \n";
1292 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1293 				op << "		do\n";
1294 				op << "			res = res.yzwx + vec4(1.0);\n";
1295 				op << "		while (++j < ${TWO});\n";
1296 				op << "	} ${DO_WHILE_POST}\n";
1297 				break;
1298 
1299 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1300 				numIters = iterCount;
1301 				op << "	${DO_WHILE_PRE}\n";
1302 				op << "	{\n";
1303 				op << "		res = coords.wxyz - vec4(1.0);\n";
1304 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1305 				op << "		while (j++ < ${TWO})\n";
1306 				op << "			res = res.yzwx + vec4(1.0);\n";
1307 				op << "		coords = res;\n";
1308 				op << "	} ${DO_WHILE_POST}\n";
1309 				break;
1310 
1311 			case LOOPCASE_PRE_FALLTHROUGH:
1312 				numIters = iterCount + 1;
1313 				op << "	int j = 3;\n";
1314 				op << "	switch (j)\n";
1315 				op << "	{\n";
1316 				op << "	case 3:\n";
1317 				op << "		res = res.yzwx + vec4(1.0);\n";
1318 				op << "	case 4:\n";
1319 				op << "		${DO_WHILE_PRE}\n";
1320 				op << "		{\n";
1321 				op << "			res = res.yzwx + vec4(1.0);\n";
1322 				op << "		} ${DO_WHILE_POST}\n";
1323 				op << "		break;\n";
1324 				op << "	}\n";
1325 				break;
1326 
1327 			case LOOPCASE_POST_FALLTHROUGH:
1328 				numIters = iterCount + 1;
1329 				op << "	int j = 3;\n";
1330 				op << "	switch (j)\n";
1331 				op << "	{\n";
1332 				op << "	case 3:\n";
1333 				op << "		${DO_WHILE_PRE}\n";
1334 				op << "		{\n";
1335 				op << "			res = res.yzwx + vec4(1.0);\n";
1336 				op << "		} ${DO_WHILE_POST}\n";
1337 				op << "	case 4:\n";
1338 				op << "		res = res.yzwx + vec4(1.0);\n";
1339 				op << "		break;\n";
1340 				op << "	}\n";
1341 				break;
1342 
1343 			case LOOPCASE_DOWHILE_TRAP:
1344 				numIters = iterCount = 3;
1345 				op << "	${DO_WHILE_PRE}\n";
1346 				op << "	{\n";
1347 				op << "		do\n";
1348 				op << "		{\n";
1349 				op << "			res = res.yzwx + vec4(1.0);\n";
1350 				op << "		} while (i >= ${THREE});\n";
1351 				op << "	} ${DO_WHILE_POST}\n";
1352 				break;
1353 
1354 			case LOOPCASE_IFBLOCK:
1355 				numIters = iterCount;
1356 				op << "	int j = 3;\n";
1357 				op << "	if (j == ${THREE})\n";
1358 				op << "	{\n";
1359 				op << "		${DO_WHILE_PRE}\n";
1360 				op << "		{\n";
1361 				op << "			res = res.yzwx + vec4(1.0);\n";
1362 				op << "		} ${DO_WHILE_POST}\n";
1363 				op << "	}\n";
1364 				op << "	else\n";
1365 				op << "	{\n";
1366 				op << "		res = res.yzwx + vec4(1.0);\n";
1367 				op << "	}\n";
1368 				break;
1369 
1370 			case LOOPCASE_ELSEBLOCK:
1371 				numIters = iterCount;
1372 				op << "	int j = 2;\n";
1373 				op << "	if (j == ${THREE})\n";
1374 				op << "	{\n";
1375 				op << "		res = res.yzwx + vec4(1.0);\n";
1376 				op << "	}\n";
1377 				op << "	else\n";
1378 				op << "	{\n";
1379 				op << "		${DO_WHILE_PRE}\n";
1380 				op << "		{\n";
1381 				op << "			res = res.yzwx + vec4(1.0);\n";
1382 				op << "		} ${DO_WHILE_POST}\n";
1383 				op << "	}\n";
1384 				break;
1385 
1386 			default:
1387 				DE_ASSERT(false);
1388 		}
1389 
1390 		doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1391 		if (loopCountType == LOOPCOUNT_CONSTANT)
1392 			doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1393 		else if (loopCountType == LOOPCOUNT_UNIFORM)
1394 			doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1395 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
1396 			doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1397 		else
1398 			DE_ASSERT(false);
1399 	}
1400 
1401 	// Shader footers.
1402 	op << "	res -= vec4(${NUM_ITERS});\n";
1403 
1404 	if (isVertexCase)
1405 	{
1406 		vtx << "	v_color = res.rgb;\n";
1407 		frag << "	o_color = vec4(v_color.rgb, 1.0);\n";
1408 	}
1409 	else
1410 	{
1411 		vtx << "	v_coords = a_coords;\n";
1412 		frag << "	o_color = vec4(res.rgb, 1.0);\n";
1413 
1414 		if (loopCountType == LOOPCOUNT_DYNAMIC)
1415 			vtx << "	v_one = a_one;\n";
1416 	}
1417 
1418 	vtx << "}\n";
1419 	frag << "}\n";
1420 
1421 	// Constants.
1422 	std::string oneStr;
1423 	std::string twoStr;
1424 	std::string threeStr;
1425 	std::string iterCountStr;
1426 	std::string numItersStr;
1427 
1428 	numItersStr = de::toString(numIters);
1429 
1430 	if (loopCountType == LOOPCOUNT_CONSTANT)
1431 	{
1432 		oneStr			= "1";
1433 		twoStr			= "2";
1434 		threeStr		= "3";
1435 		iterCountStr	= de::toString(iterCount);
1436 	}
1437 	else if (loopCountType == LOOPCOUNT_UNIFORM)
1438 	{
1439 		oneStr			= "ui_one";
1440 		twoStr			= "ui_two";
1441 		threeStr		= "ui_three";
1442 		iterCountStr	= getIntUniformName(iterCount);
1443 	}
1444 	else if (loopCountType == LOOPCOUNT_DYNAMIC)
1445 	{
1446 		oneStr			= "one*ui_one";
1447 		twoStr			= "one*ui_two";
1448 		threeStr		= "one*ui_three";
1449 		iterCountStr	= std::string("one*") + getIntUniformName(iterCount);
1450 	}
1451 	else DE_ASSERT(false);
1452 
1453 	// Fill in shader templates.
1454 	std::map<std::string, std::string> params;
1455 	params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1456 	params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1457 	params.insert(std::pair<std::string, std::string>("NUM_ITERS", numItersStr));
1458 	params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1459 	params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1460 	params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1461 	params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1462 	params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1463 	params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1464 	params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1465 	params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1466 
1467 	tcu::StringTemplate vertTemplate(vtx.str());
1468 	tcu::StringTemplate fragTemplate(frag.str());
1469 	std::string vertexShaderSource = vertTemplate.specialize(params);
1470 	std::string fragmentShaderSource = fragTemplate.specialize(params);
1471 
1472 	// Create the case.
1473 	UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1474 	ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1475 	return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1476 }
1477 
1478 class ShaderLoopTests : public tcu::TestCaseGroup
1479 {
1480 public:
1481 							ShaderLoopTests			(tcu::TestContext& testCtx);
1482 	virtual					~ShaderLoopTests		(void);
1483 
1484 	virtual void			init					(void);
1485 
1486 private:
1487 							ShaderLoopTests			(const ShaderLoopTests&);		// not allowed!
1488 	ShaderLoopTests&		operator=				(const ShaderLoopTests&);		// not allowed!
1489 };
1490 
ShaderLoopTests(tcu::TestContext & testCtx)1491 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1492 		: TestCaseGroup(testCtx, "loops", "Loop Tests")
1493 {
1494 }
1495 
~ShaderLoopTests(void)1496 ShaderLoopTests::~ShaderLoopTests (void)
1497 {
1498 }
1499 
init(void)1500 void ShaderLoopTests::init (void)
1501 {
1502 	// Loop cases.
1503 
1504 	static const glu::ShaderType s_shaderTypes[] =
1505 	{
1506 		glu::SHADERTYPE_VERTEX,
1507 		glu::SHADERTYPE_FRAGMENT
1508 	};
1509 
1510 	static const glu::DataType s_countDataType[] =
1511 	{
1512 		glu::TYPE_INT,
1513 		glu::TYPE_FLOAT
1514 	};
1515 
1516 	TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
1517 	TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
1518 	addChild(genericGroup);
1519 	addChild(specialGroup);
1520 
1521 	for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1522 	{
1523 		const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1524 
1525 		for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1526 		{
1527 			const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1528 
1529 			std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1530 			std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1531 			TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1532 			TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1533 			genericGroup->addChild(genericSubGroup);
1534 			specialGroup->addChild(specialSubGroup);
1535 
1536 			// Generic cases.
1537 
1538 			for (int precision = glu::PRECISION_MEDIUMP; precision < glu::PRECISION_LAST; precision++)
1539 			{
1540 				const char* precisionName = getPrecisionName((glu::Precision)precision);
1541 
1542 				for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1543 				{
1544 					glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1545 					const char* dataTypeName = getDataTypeName(loopDataType);
1546 
1547 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1548 					{
1549 						glu::ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1550 						const char*	shaderTypeName	= getShaderTypeName(shaderType);
1551 						bool		isVertexCase	= (shaderType == glu::SHADERTYPE_VERTEX);
1552 
1553 						std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1554 						std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
1555 						de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1556 						genericSubGroup->addChild(testCase.release());
1557 					}
1558 				}
1559 			}
1560 
1561 			// Special cases.
1562 
1563 			for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1564 			{
1565 				const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1566 
1567 				// no-iterations not possible with do-while.
1568 				if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1569 					continue;
1570 
1571 				for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1572 				{
1573 					glu::ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1574 					const char*	shaderTypeName	= getShaderTypeName(shaderType);
1575 					bool		isVertexCase	= (shaderType == glu::SHADERTYPE_VERTEX);
1576 
1577 					std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1578 					std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
1579 					de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1580 					specialSubGroup->addChild(testCase.release());
1581 				}
1582 			}
1583 		}
1584 	}
1585 }
1586 
1587 } // anonymous
1588 
createLoopTests(tcu::TestContext & testCtx)1589 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1590 {
1591 	return new ShaderLoopTests(testCtx);
1592 }
1593 
1594 
1595 } // sr
1596 } // vkt
1597