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, 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 					 bool				isVertexCase,
271 					 ShaderEvalFunc		evalFunc,
272 					 UniformSetup*		uniformSetup,
273 					 const std::string&	vertexShaderSource,
274 					 const std::string&	fragmentShaderSource)
275 		: ShaderRenderCase		(testCtx, name, isVertexCase, evalFunc, uniformSetup, DE_NULL)
276 	{
277 		m_vertShaderSource = vertexShaderSource;
278 		m_fragShaderSource = fragmentShaderSource;
279 	}
280 };
281 
282 // Uniform setup tools
283 
284 class LoopUniformSetup : public UniformSetup
285 {
286 public:
LoopUniformSetup(std::vector<BaseUniformType>& types)287 									LoopUniformSetup	(std::vector<BaseUniformType>& types)
288 										: m_uniformInformations(types)
289 									{}
290 
291 	virtual void					setup				(ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
292 
293 private:
294 	std::vector<BaseUniformType>	m_uniformInformations;
295 };
296 
setup(ShaderRenderCaseInstance& instance, const tcu::Vec4&) const297 void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
298 {
299 	for (size_t i = 0; i < m_uniformInformations.size(); i++)
300 	{
301 		instance.useUniform((deUint32)i, m_uniformInformations[i]);
302 	}
303 }
304 
305 // Testcase builders
306 
createGenericLoopCase(tcu::TestContext& testCtx, const std::string& caseName, bool isVertexCase, LoopType loopType, LoopCountType loopCountType, glu::Precision loopCountPrecision, glu::DataType loopCountDataType)307 static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext&	testCtx,
308 														const std::string&	caseName,
309 														bool				isVertexCase,
310 														LoopType			loopType,
311 														LoopCountType		loopCountType,
312 														glu::Precision		loopCountPrecision,
313 														glu::DataType		loopCountDataType)
314 {
315 	std::ostringstream vtx;
316 	std::ostringstream frag;
317 	std::ostringstream& op = isVertexCase ? vtx : frag;
318 
319 	vtx << "#version 310 es\n";
320 	frag << "#version 310 es\n";
321 
322 	vtx << "layout(location=0) in highp vec4 a_position;\n";
323 	vtx << "layout(location=1) in highp vec4 a_coords;\n";
324 	frag << "layout(location=0) out mediump vec4 o_color;\n";
325 
326 	if (loopCountType == LOOPCOUNT_DYNAMIC)
327 		vtx << "layout(location=3) in mediump float a_one;\n";
328 
329 	if (isVertexCase)
330 	{
331 		vtx << "layout(location=0) out mediump vec3 v_color;\n";
332 		frag << "layout(location=0) in mediump vec3 v_color;\n";
333 	}
334 	else
335 	{
336 		vtx << "layout(location=0) out mediump vec4 v_coords;\n";
337 		frag << "layout(location=0) in mediump vec4 v_coords;\n";
338 
339 		if (loopCountType == LOOPCOUNT_DYNAMIC)
340 		{
341 			vtx << "layout(location=1) out mediump float v_one;\n";
342 			frag << "layout(location=1) in mediump float v_one;\n";
343 		}
344 	}
345 
346 	const int	numLoopIters = 3;
347 	const bool	isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
348 	deUint32	locationCounter = 0;
349 	std::vector<BaseUniformType> uniformInformations;
350 
351 	if (isIntCounter)
352 	{
353 		if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
354 		{
355 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
356 			op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
357 			op << "};\n";
358 			uniformInformations.push_back(getIntUniformType(numLoopIters));
359 			locationCounter++;
360 		}
361 	}
362 	else
363 	{
364 		if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
365 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
366 			op << "	${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
367 			op << "};\n";
368 			uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
369 			locationCounter++;
370 		}
371 
372 		if (numLoopIters != 1){
373 			op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
374 			op << "	${COUNTER_PRECISION} float uf_one;\n";
375 			op << "};\n";
376 			uniformInformations.push_back(UF_ONE);
377 			locationCounter++;
378 		}
379 	}
380 
381 	vtx << "\n";
382 	vtx << "void main()\n";
383 	vtx << "{\n";
384 	vtx << "	gl_Position = a_position;\n";
385 
386 	frag << "\n";
387 	frag << "void main()\n";
388 	frag << "{\n";
389 
390 	if (isVertexCase)
391 		vtx << "	${PRECISION} vec4 coords = a_coords;\n";
392 	else
393 		frag << "	${PRECISION} vec4 coords = v_coords;\n";
394 
395 
396 	if (loopCountType == LOOPCOUNT_DYNAMIC)
397 	{
398 		if (isIntCounter)
399 		{
400 			if (isVertexCase)
401 				vtx << "	${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
402 			else
403 				frag << "	${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
404 		}
405 		else
406 		{
407 			if (isVertexCase)
408 				vtx << "	${COUNTER_PRECISION} float one = a_one;\n";
409 			else
410 				frag << "	${COUNTER_PRECISION} float one = v_one;\n";
411 		}
412 	}
413 
414 	// Read array.
415 	op << "	${PRECISION} vec4 res = coords;\n";
416 
417 	// Loop iteration count.
418 	std::string	iterMaxStr;
419 
420 	if (isIntCounter)
421 	{
422 		if (loopCountType == LOOPCOUNT_CONSTANT)
423 			iterMaxStr = de::toString(numLoopIters);
424 		else if (loopCountType == LOOPCOUNT_UNIFORM)
425 			iterMaxStr = getIntUniformName(numLoopIters);
426 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
427 			iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
428 		else
429 			DE_ASSERT(false);
430 	}
431 	else
432 	{
433 		if (loopCountType == LOOPCOUNT_CONSTANT)
434 			iterMaxStr = "1.0";
435 		else if (loopCountType == LOOPCOUNT_UNIFORM)
436 			iterMaxStr = "uf_one";
437 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
438 			iterMaxStr = "uf_one*one";
439 		else
440 			DE_ASSERT(false);
441 	}
442 
443 	// Loop operations.
444 	std::string initValue			= isIntCounter ? "0" : "0.05";
445 	std::string loopCountDeclStr	= "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
446 	std::string loopCmpStr			= ("ndx < " + iterMaxStr);
447 	std::string incrementStr;
448 	if (isIntCounter)
449 		incrementStr = "ndx++";
450 	else
451 	{
452 		if (loopCountType == LOOPCOUNT_CONSTANT)
453 			incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
454 		else if (loopCountType == LOOPCOUNT_UNIFORM)
455 			incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
456 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
457 			incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
458 		else
459 			DE_ASSERT(false);
460 	}
461 
462 	// Loop body.
463 	std::string loopBody;
464 
465 	loopBody = "		res = res.yzwx + vec4(1.0);\n";
466 
467 	if (loopType == LOOPTYPE_FOR)
468 	{
469 		op << "	for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
470 		op << "	{\n";
471 		op << loopBody;
472 		op << "	}\n";
473 	}
474 	else if (loopType == LOOPTYPE_WHILE)
475 	{
476 		op << "\t" << loopCountDeclStr + ";\n";
477 		op << "	while (" + loopCmpStr + ")\n";
478 		op << "	{\n";
479 		op << loopBody;
480 		op << "\t\t" + incrementStr + ";\n";
481 		op << "	}\n";
482 	}
483 	else if (loopType == LOOPTYPE_DO_WHILE)
484 	{
485 		op << "\t" << loopCountDeclStr + ";\n";
486 		op << "	do\n";
487 		op << "	{\n";
488 		op << loopBody;
489 		op << "\t\t" + incrementStr + ";\n";
490 		op << "	} while (" + loopCmpStr + ");\n";
491 	}
492 	else
493 		DE_ASSERT(false);
494 
495 	op << "	res -= vec4(" + de::toString(numLoopIters) + ");\n";
496 
497 	if (isVertexCase)
498 	{
499 		vtx << "	v_color = res.rgb;\n";
500 		frag << "	o_color = vec4(v_color.rgb, 1.0);\n";
501 	}
502 	else
503 	{
504 		vtx << "	v_coords = a_coords;\n";
505 		frag << "	o_color = vec4(res.rgb, 1.0);\n";
506 
507 		if (loopCountType == LOOPCOUNT_DYNAMIC)
508 			vtx << "	v_one = a_one;\n";
509 	}
510 
511 	vtx << "}\n";
512 	frag << "}\n";
513 
514 	// Fill in shader templates.
515 	std::map<std::string, std::string> params;
516 	params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
517 	params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
518 	params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
519 
520 	tcu::StringTemplate vertTemplate(vtx.str());
521 	tcu::StringTemplate fragTemplate(frag.str());
522 	std::string vertexShaderSource = vertTemplate.specialize(params);
523 	std::string fragmentShaderSource = fragTemplate.specialize(params);
524 
525 	// Create the case.
526 	ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
527 	UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
528 	return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
529 }
530 
createSpecialLoopCase(tcu::TestContext& testCtx, const std::string& caseName, bool isVertexCase, LoopCase loopCase, LoopType loopType, LoopCountType loopCountType)531 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext&	testCtx,
532 														const std::string&	caseName,
533 														bool				isVertexCase,
534 														LoopCase			loopCase,
535 														LoopType			loopType,
536 														LoopCountType		loopCountType)
537 {
538 	std::ostringstream vtx;
539 	std::ostringstream frag;
540 	std::ostringstream& op = isVertexCase ? vtx : frag;
541 
542 	std::vector<BaseUniformType>	uniformInformations;
543 	deUint32						locationCounter = 0;
544 
545 	vtx << "#version 310 es\n";
546 	frag << "#version 310 es\n";
547 
548 	vtx << "layout(location=0) in highp vec4 a_position;\n";
549 	vtx << "layout(location=1) in highp vec4 a_coords;\n";
550 	frag << "layout(location=0) out mediump vec4 o_color;\n";
551 
552 	if (loopCountType == LOOPCOUNT_DYNAMIC)
553 		vtx << "layout(location=3) in mediump float a_one;\n";
554 
555 	if (isVertexCase)
556 	{
557 		vtx << "layout(location=0) out mediump vec3 v_color;\n";
558 		frag << "layout(location=0) in mediump vec3 v_color;\n";
559 	}
560 	else
561 	{
562 		vtx << "layout(location=0) out mediump vec4 v_coords;\n";
563 		frag << "layout(location=0) in mediump vec4 v_coords;\n";
564 
565 		if (loopCountType == LOOPCOUNT_DYNAMIC)
566 		{
567 			vtx << "layout(location=1) out mediump float v_one;\n";
568 			frag << "layout(location=1) in mediump float v_one;\n";
569 		}
570 	}
571 
572 	if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
573 		op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
574 		op << "  bool ub_true;\n";
575 		op << "};\n";
576 		uniformInformations.push_back(UB_TRUE);
577 		locationCounter++;
578 	}
579 
580 	struct
581 	{
582 		char const*		name;
583 		BaseUniformType	type;
584 	} uniforms[] =
585 	{
586 		{ "ui_zero",	UI_ZERO },
587 		{ "ui_one",		UI_ONE },
588 		{ "ui_two",		UI_TWO },
589 		{ "ui_three",	UI_THREE },
590 		{ "ui_four",	UI_FOUR },
591 		{ "ui_five",	UI_FIVE },
592 		{ "ui_six",		UI_SIX  },
593 	};
594 
595 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
596 	{
597 		op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
598 		op << "  ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
599 		op << "};\n";
600 		uniformInformations.push_back(uniforms[i].type);
601 		locationCounter++;
602 	}
603 
604 	if (loopCase == LOOPCASE_101_ITERATIONS) {
605 
606 		op << "layout(std140, set=0, binding=" << locationCounter <<  ") uniform buff" << locationCounter << " {\n";
607 		op << "  ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
608 		op << "};\n";
609 		uniformInformations.push_back(UI_ONEHUNDREDONE);
610 		locationCounter++;
611 	}
612 
613 	int iterCount	= 3;	// value to use in loop
614 	int numIters	= 3;	// actual number of iterations
615 
616 	vtx << "\n";
617 	vtx << "void main()\n";
618 	vtx << "{\n";
619 	vtx << "	gl_Position = a_position;\n";
620 
621 	frag << "\n";
622 	frag << "void main()\n";
623 	frag << "{\n";
624 
625 	if (loopCountType == LOOPCOUNT_DYNAMIC)
626 	{
627 		if (isVertexCase)
628 			vtx << "	${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
629 		else
630 			frag << "	${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
631 	}
632 
633 	if (isVertexCase)
634 		vtx << "	${PRECISION} vec4 coords = a_coords;\n";
635 	else
636 		frag << "	${PRECISION} vec4 coords = v_coords;\n";
637 
638 	// Read array.
639 	op << "	${PRECISION} vec4 res = coords;\n";
640 
641 	// Handle all loop types.
642 	std::string counterPrecisionStr = "mediump";
643 	std::string forLoopStr;
644 	std::string whileLoopStr;
645 	std::string doWhileLoopPreStr;
646 	std::string doWhileLoopPostStr;
647 
648 	if (loopType == LOOPTYPE_FOR)
649 	{
650 		switch (loopCase)
651 		{
652 			case LOOPCASE_EMPTY_BODY:
653 				numIters = 0;
654 				op << "	${FOR_LOOP} {}\n";
655 				break;
656 
657 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
658 				numIters = 0;
659 				op << "	for (;;) { break; res = res.yzwx + vec4(1.0); }\n";
660 				break;
661 
662 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
663 				numIters = 1;
664 				op << "	for (;;) { res = res.yzwx + vec4(1.0); break; }\n";
665 				break;
666 
667 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
668 				numIters = 2;
669 				op << "	${COUNTER_PRECISION} int i = 0;\n";
670 				op << "	for (;;) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
671 				break;
672 
673 			case LOOPCASE_SINGLE_STATEMENT:
674 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
675 				break;
676 
677 			case LOOPCASE_COMPOUND_STATEMENT:
678 				iterCount	= 2;
679 				numIters	= 2 * iterCount;
680 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
681 				break;
682 
683 			case LOOPCASE_SEQUENCE_STATEMENT:
684 				iterCount	= 2;
685 				numIters	= 2 * iterCount;
686 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
687 				break;
688 
689 			case LOOPCASE_NO_ITERATIONS:
690 				iterCount	= 0;
691 				numIters	= 0;
692 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
693 				break;
694 
695 			case LOOPCASE_SINGLE_ITERATION:
696 				iterCount	= 1;
697 				numIters	= 1;
698 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
699 				break;
700 
701 			case LOOPCASE_SELECT_ITERATION_COUNT:
702 				op << "	for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx + vec4(1.0);\n";
703 				break;
704 
705 			case LOOPCASE_CONDITIONAL_CONTINUE:
706 				numIters = iterCount - 1;
707 				op << "	${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
708 				break;
709 
710 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
711 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
712 				break;
713 
714 			case LOOPCASE_ONLY_CONTINUE:
715 				numIters = 0;
716 				op << "	${FOR_LOOP} { continue; }\n";
717 				break;
718 
719 			case LOOPCASE_DOUBLE_CONTINUE:
720 				numIters = iterCount - 1;
721 				op << "	${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
722 				break;
723 
724 			case LOOPCASE_CONDITIONAL_BREAK:
725 				numIters = 2;
726 				op << "	${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx + vec4(1.0); }\n";
727 				break;
728 
729 			case LOOPCASE_UNCONDITIONAL_BREAK:
730 				numIters = 1;
731 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
732 				break;
733 
734 			case LOOPCASE_PRE_INCREMENT:
735 				op << "	for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx + vec4(1.0); }\n";
736 				break;
737 
738 			case LOOPCASE_POST_INCREMENT:
739 				op << "	${FOR_LOOP} { res = res.yzwx + vec4(1.0); }\n";
740 				break;
741 
742 			case LOOPCASE_MIXED_BREAK_CONTINUE:
743 				numIters	= 2;
744 				iterCount	= 5;
745 				op << "	${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
746 				break;
747 
748 			case LOOPCASE_VECTOR_COUNTER:
749 				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";
750 				break;
751 
752 			case LOOPCASE_101_ITERATIONS:
753 				numIters = iterCount = 101;
754 				op << "	${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
755 				break;
756 
757 			case LOOPCASE_SEQUENCE:
758 				iterCount	= 5;
759 				numIters	= 5;
760 				op << "	${COUNTER_PRECISION} int i;\n";
761 				op << "	for (i = 0; i < ${TWO}; i++) { res = res.yzwx + vec4(1.0); }\n";
762 				op << "	for (; i < ${ITER_COUNT}; i++) { res = res.yzwx + vec4(1.0); }\n";
763 				break;
764 
765 			case LOOPCASE_NESTED:
766 				numIters = 2 * iterCount;
767 				op << "	for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
768 				op << "	{\n";
769 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
770 				op << "			res = res.yzwx + vec4(1.0);\n";
771 				op << "	}\n";
772 				break;
773 
774 			case LOOPCASE_NESTED_SEQUENCE:
775 				numIters = 3 * iterCount;
776 				op << "	for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
777 				op << "	{\n";
778 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
779 				op << "			res = res.yzwx + vec4(1.0);\n";
780 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
781 				op << "			res = res.yzwx + vec4(1.0);\n";
782 				op << "	}\n";
783 				break;
784 
785 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
786 				numIters = 2;
787 				op << "	${FOR_LOOP}\n";
788 				op << "	{\n";
789 				op << "		res = coords; // ignore outer loop effect \n";
790 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
791 				op << "			res = res.yzwx + vec4(1.0);\n";
792 				op << "	}\n";
793 				break;
794 
795 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
796 				numIters = iterCount;
797 				op << "	${FOR_LOOP}\n";
798 				op << "	{\n";
799 				op << "		res = coords.wxyz - vec4(1.0);\n";
800 				op << "		for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
801 				op << "			res = res.yzwx + vec4(1.0);\n";
802 				op << "		coords = res;\n";
803 				op << "	}\n";
804 				break;
805 
806 			case LOOPCASE_PRE_FALLTHROUGH:
807 				numIters = iterCount + 1;
808 				op << "	int j = 3;\n";
809 				op << "	switch (j)\n";
810 				op << "	{\n";
811 				op << "	case 3:\n";
812 				op << "		res = res.yzwx + vec4(1.0);\n";
813 				op << "	case 4:\n";
814 				op << "		${FOR_LOOP}\n";
815 				op << "			res = res.yzwx + vec4(1.0);\n";
816 				op << "		break;\n";
817 				op << "	}\n";
818 				break;
819 
820 			case LOOPCASE_POST_FALLTHROUGH:
821 				numIters = iterCount + 1;
822 				op << "	int j = 3;\n";
823 				op << "	switch (j)\n";
824 				op << "	{\n";
825 				op << "	case 3:\n";
826 				op << "		${FOR_LOOP}\n";
827 				op << "			res = res.yzwx + vec4(1.0);\n";
828 				op << "	case 4:\n";
829 				op << "		res = res.yzwx + vec4(1.0);\n";
830 				op << "		break;\n";
831 				op << "	}\n";
832 				break;
833 
834 			case LOOPCASE_DOWHILE_TRAP:
835 				numIters = iterCount = 3;
836 				op << "	${FOR_LOOP}\n";
837 				op << "	{\n";
838 				op << "		do\n";
839 				op << "		{\n";
840 				op << "			res = res.yzwx + vec4(1.0);\n";
841 				op << "		} while (i >= ${THREE});\n";
842 				op << "	}\n";
843 				break;
844 
845 			case LOOPCASE_IFBLOCK:
846 				numIters = iterCount;
847 				op << "	int j = 3;\n";
848 				op << "	if (j == ${THREE})\n";
849 				op << "	{\n";
850 				op << "		${FOR_LOOP}\n";
851 				op << "			res = res.yzwx + vec4(1.0);\n";
852 				op << "	}\n";
853 				op << "	else\n";
854 				op << "	{\n";
855 				op << "		res = res.yzwx + vec4(1.0);\n";
856 				op << "	}\n";
857 				break;
858 
859 			case LOOPCASE_ELSEBLOCK:
860 				numIters = iterCount;
861 				op << "	int j = 2;\n";
862 				op << "	if (j == ${THREE})\n";
863 				op << "	{\n";
864 				op << "		res = res.yzwx + vec4(1.0);\n";
865 				op << "	}\n";
866 				op << "	else\n";
867 				op << "	{\n";
868 				op << "		${FOR_LOOP}\n";
869 				op << "			res = res.yzwx + vec4(1.0);\n";
870 				op << "	}\n";
871 				break;
872 
873 			default:
874 				DE_ASSERT(false);
875 		}
876 
877 		if (loopCountType == LOOPCOUNT_CONSTANT)
878 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
879 		else if (loopCountType == LOOPCOUNT_UNIFORM)
880 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
881 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
882 			forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
883 		else
884 			DE_ASSERT(false);
885 	}
886 	else if (loopType == LOOPTYPE_WHILE)
887 	{
888 		switch (loopCase)
889 		{
890 			case LOOPCASE_EMPTY_BODY:
891 				numIters = 0;
892 				op << "	${WHILE_LOOP} {}\n";
893 				break;
894 
895 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
896 				numIters = 0;
897 				op << "	while (true) { break; res = res.yzwx + vec4(1.0); }\n";
898 				break;
899 
900 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
901 				numIters = 1;
902 				op << "	while (true) { res = res.yzwx + vec4(1.0); break; }\n";
903 				break;
904 
905 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
906 				numIters = 2;
907 				op << "	${COUNTER_PRECISION} int i = 0;\n";
908 				op << "	while (true) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
909 				break;
910 
911 			case LOOPCASE_SINGLE_STATEMENT:
912 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
913 				break;
914 
915 			case LOOPCASE_COMPOUND_STATEMENT:
916 				iterCount	= 2;
917 				numIters	= 2 * iterCount;
918 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
919 				break;
920 
921 			case LOOPCASE_SEQUENCE_STATEMENT:
922 				iterCount	= 2;
923 				numIters	= 2 * iterCount;
924 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
925 				break;
926 
927 			case LOOPCASE_NO_ITERATIONS:
928 				iterCount	= 0;
929 				numIters	= 0;
930 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
931 				break;
932 
933 			case LOOPCASE_SINGLE_ITERATION:
934 				iterCount	= 1;
935 				numIters	= 1;
936 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
937 				break;
938 
939 			case LOOPCASE_SELECT_ITERATION_COUNT:
940 				op << "	${COUNTER_PRECISION} int i = 0;\n";
941 				op << "	while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx + vec4(1.0); i++; }\n";
942 				break;
943 
944 			case LOOPCASE_CONDITIONAL_CONTINUE:
945 				numIters = iterCount - 1;
946 				op << "	${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
947 				break;
948 
949 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
950 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
951 				break;
952 
953 			case LOOPCASE_ONLY_CONTINUE:
954 				numIters = 0;
955 				op << "	${WHILE_LOOP} { continue; }\n";
956 				break;
957 
958 			case LOOPCASE_DOUBLE_CONTINUE:
959 				numIters = iterCount - 1;
960 				op << "	${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
961 				break;
962 
963 			case LOOPCASE_CONDITIONAL_BREAK:
964 				numIters = 2;
965 				op << "	${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx + vec4(1.0); }\n";
966 				break;
967 
968 			case LOOPCASE_UNCONDITIONAL_BREAK:
969 				numIters = 1;
970 				op << "	${WHILE_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
971 				break;
972 
973 			case LOOPCASE_PRE_INCREMENT:
974 				numIters = iterCount - 1;
975 				op << "	${COUNTER_PRECISION} int i = 0;\n";
976 				op << "	while (++i < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
977 				break;
978 
979 			case LOOPCASE_POST_INCREMENT:
980 				op << "	${COUNTER_PRECISION} int i = 0;\n";
981 				op << "	while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
982 				break;
983 
984 			case LOOPCASE_MIXED_BREAK_CONTINUE:
985 				numIters	= 2;
986 				iterCount	= 5;
987 				op << "	${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
988 				break;
989 
990 			case LOOPCASE_VECTOR_COUNTER:
991 				op << "	${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
992 				op << "	while (i.x < i.z) { res = res.yzwx + vec4(1.0); i.x += i.y; }\n";
993 				break;
994 
995 			case LOOPCASE_101_ITERATIONS:
996 				numIters = iterCount = 101;
997 				op << "	${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
998 				break;
999 
1000 			case LOOPCASE_SEQUENCE:
1001 				iterCount	= 6;
1002 				numIters	= iterCount - 1;
1003 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1004 				op << "	while (i++ < ${TWO}) { res = res.yzwx + vec4(1.0); }\n";
1005 				op << "	while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n"; // \note skips one iteration
1006 				break;
1007 
1008 			case LOOPCASE_NESTED:
1009 				numIters = 2 * iterCount;
1010 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1011 				op << "	while (i++ < ${TWO})\n";
1012 				op << "	{\n";
1013 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1014 				op << "		while (j++ < ${ITER_COUNT})\n";
1015 				op << "			res = res.yzwx + vec4(1.0);\n";
1016 				op << "	}\n";
1017 				break;
1018 
1019 			case LOOPCASE_NESTED_SEQUENCE:
1020 				numIters = 2 * iterCount;
1021 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1022 				op << "	while (i++ < ${ITER_COUNT})\n";
1023 				op << "	{\n";
1024 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1025 				op << "		while (j++ < ${ONE})\n";
1026 				op << "			res = res.yzwx + vec4(1.0);\n";
1027 				op << "		while (j++ < ${THREE})\n"; // \note skips one iteration
1028 				op << "			res = res.yzwx + vec4(1.0);\n";
1029 				op << "	}\n";
1030 				break;
1031 
1032 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1033 				numIters = 2;
1034 				op << "	${WHILE_LOOP}\n";
1035 				op << "	{\n";
1036 				op << "		res = coords; // ignore outer loop effect \n";
1037 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1038 				op << "		while (j++ < ${TWO})\n";
1039 				op << "			res = res.yzwx + vec4(1.0);\n";
1040 				op << "	}\n";
1041 				break;
1042 
1043 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1044 				numIters = iterCount;
1045 				op << "	${WHILE_LOOP}\n";
1046 				op << "	{\n";
1047 				op << "		res = coords.wxyz - vec4(1.0);\n";
1048 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1049 				op << "		while (j++ < ${TWO})\n";
1050 				op << "			res = res.yzwx + vec4(1.0);\n";
1051 				op << "		coords = res;\n";
1052 				op << "	}\n";
1053 				break;
1054 
1055 			case LOOPCASE_PRE_FALLTHROUGH:
1056 				numIters = iterCount + 1;
1057 				op << "	int j = 3;\n";
1058 				op << "	switch (j)\n";
1059 				op << "	{\n";
1060 				op << "	case 3:\n";
1061 				op << "		res = res.yzwx + vec4(1.0);\n";
1062 				op << "	case 4:\n";
1063 				op << "		${WHILE_LOOP}\n";
1064 				op << "			res = res.yzwx + vec4(1.0);\n";
1065 				op << "		break;\n";
1066 				op << "	}\n";
1067 				break;
1068 
1069 			case LOOPCASE_POST_FALLTHROUGH:
1070 				numIters = iterCount + 1;
1071 				op << "	int j = 3;\n";
1072 				op << "	switch (j)\n";
1073 				op << "	{\n";
1074 				op << "	case 3:\n";
1075 				op << "		${WHILE_LOOP}\n";
1076 				op << "			res = res.yzwx + vec4(1.0);\n";
1077 				op << "	case 4:\n";
1078 				op << "		res = res.yzwx + vec4(1.0);\n";
1079 				op << "		break;\n";
1080 				op << "	}\n";
1081 				break;
1082 
1083 			case LOOPCASE_DOWHILE_TRAP:
1084 				numIters = iterCount = 3;
1085 				op << "	${WHILE_LOOP}\n";
1086 				op << "	{\n";
1087 				op << "		do\n";
1088 				op << "		{\n";
1089 				op << "			res = res.yzwx + vec4(1.0);\n";
1090 				op << "		} while (i > ${THREE});\n";
1091 				op << "	}\n";
1092 				break;
1093 
1094 			case LOOPCASE_IFBLOCK:
1095 				numIters = iterCount;
1096 				op << "	int j = 3;\n";
1097 				op << "	if (j == ${THREE})\n";
1098 				op << "	{\n";
1099 				op << "		${WHILE_LOOP}\n";
1100 				op << "			res = res.yzwx + vec4(1.0);\n";
1101 				op << "	}\n";
1102 				op << "	else\n";
1103 				op << "	{\n";
1104 				op << "		res = res.yzwx + vec4(1.0);\n";
1105 				op << "	}\n";
1106 				break;
1107 
1108 			case LOOPCASE_ELSEBLOCK:
1109 				numIters = iterCount;
1110 				op << "	int j = 2;\n";
1111 				op << "	if (j == ${THREE})\n";
1112 				op << "	{\n";
1113 				op << "		res = res.yzwx + vec4(1.0);\n";
1114 				op << "	}\n";
1115 				op << "	else\n";
1116 				op << "	{\n";
1117 				op << "		${WHILE_LOOP}\n";
1118 				op << "			res = res.yzwx + vec4(1.0);\n";
1119 				op << "	}\n";
1120 				break;
1121 
1122 			default:
1123 				DE_ASSERT(false);
1124 		}
1125 
1126 		if (loopCountType == LOOPCOUNT_CONSTANT)
1127 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < " + de::toString(iterCount) + ")";
1128 		else if (loopCountType == LOOPCOUNT_UNIFORM)
1129 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < " + getIntUniformName(iterCount) + ")";
1130 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
1131 			whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "	while(i++ < one*" + getIntUniformName(iterCount) + ")";
1132 		else
1133 			DE_ASSERT(false);
1134 	}
1135 	else
1136 	{
1137 		DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
1138 
1139 		switch (loopCase)
1140 		{
1141 			case LOOPCASE_EMPTY_BODY:
1142 				numIters = 0;
1143 				op << "	${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1144 				break;
1145 
1146 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1147 				numIters = 0;
1148 				op << "	do { break; res = res.yzwx + vec4(1.0); } while (true);\n";
1149 				break;
1150 
1151 			case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1152 				numIters = 1;
1153 				op << "	do { res = res.yzwx + vec4(1.0); break; } while (true);\n";
1154 				break;
1155 
1156 			case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1157 				numIters = 2;
1158 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1159 				op << "	do { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; } while (true);\n";
1160 				break;
1161 
1162 			case LOOPCASE_SINGLE_STATEMENT:
1163 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1164 				break;
1165 
1166 			case LOOPCASE_COMPOUND_STATEMENT:
1167 				iterCount	= 2;
1168 				numIters	= 2 * iterCount;
1169 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1170 				break;
1171 
1172 			case LOOPCASE_SEQUENCE_STATEMENT:
1173 				iterCount	= 2;
1174 				numIters	= 2 * iterCount;
1175 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1176 				break;
1177 
1178 			case LOOPCASE_NO_ITERATIONS:
1179 				DE_ASSERT(false);
1180 				break;
1181 
1182 			case LOOPCASE_SINGLE_ITERATION:
1183 				iterCount	= 1;
1184 				numIters	= 1;
1185 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1186 				break;
1187 
1188 			case LOOPCASE_SELECT_ITERATION_COUNT:
1189 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1190 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1191 				break;
1192 
1193 			case LOOPCASE_CONDITIONAL_CONTINUE:
1194 				numIters = iterCount - 1;
1195 				op << "	${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1196 				break;
1197 
1198 			case LOOPCASE_UNCONDITIONAL_CONTINUE:
1199 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
1200 				break;
1201 
1202 			case LOOPCASE_ONLY_CONTINUE:
1203 				numIters = 0;
1204 				op << "	${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1205 				break;
1206 
1207 			case LOOPCASE_DOUBLE_CONTINUE:
1208 				numIters = iterCount - 1;
1209 				op << "	${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
1210 				break;
1211 
1212 			case LOOPCASE_CONDITIONAL_BREAK:
1213 				numIters = 2;
1214 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1215 				break;
1216 
1217 			case LOOPCASE_UNCONDITIONAL_BREAK:
1218 				numIters = 1;
1219 				op << "	${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); break; } ${DO_WHILE_POST}\n";
1220 				break;
1221 
1222 			case LOOPCASE_PRE_INCREMENT:
1223 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1224 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
1225 				break;
1226 
1227 			case LOOPCASE_POST_INCREMENT:
1228 				numIters = iterCount + 1;
1229 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1230 				op << "	do { res = res.yzwx + vec4(1.0); } while (i++ < ${ITER_COUNT});\n";
1231 				break;
1232 
1233 			case LOOPCASE_MIXED_BREAK_CONTINUE:
1234 				numIters	= 2;
1235 				iterCount	= 5;
1236 				op << "	${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
1237 				break;
1238 
1239 			case LOOPCASE_VECTOR_COUNTER:
1240 				op << "	${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1241 				op << "	do { res = res.yzwx + vec4(1.0); } while ((i.x += i.y) < i.z);\n";
1242 				break;
1243 
1244 			case LOOPCASE_101_ITERATIONS:
1245 				numIters = iterCount = 101;
1246 				op << "	${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
1247 				break;
1248 
1249 			case LOOPCASE_SEQUENCE:
1250 				iterCount	= 5;
1251 				numIters	= 5;
1252 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1253 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${TWO});\n";
1254 				op << "	do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
1255 				break;
1256 
1257 			case LOOPCASE_NESTED:
1258 				numIters = 2 * iterCount;
1259 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1260 				op << "	do\n";
1261 				op << "	{\n";
1262 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1263 				op << "		do\n";
1264 				op << "			res = res.yzwx + vec4(1.0);\n";
1265 				op << "		while (++j < ${ITER_COUNT});\n";
1266 				op << "	} while (++i < ${TWO});\n";
1267 				break;
1268 
1269 			case LOOPCASE_NESTED_SEQUENCE:
1270 				numIters = 3 * iterCount;
1271 				op << "	${COUNTER_PRECISION} int i = 0;\n";
1272 				op << "	do\n";
1273 				op << "	{\n";
1274 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1275 				op << "		do\n";
1276 				op << "			res = res.yzwx + vec4(1.0);\n";
1277 				op << "		while (++j < ${TWO});\n";
1278 				op << "		do\n";
1279 				op << "			res = res.yzwx + vec4(1.0);\n";
1280 				op << "		while (++j < ${THREE});\n";
1281 				op << "	} while (++i < ${ITER_COUNT});\n";
1282 				break;
1283 
1284 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1285 				numIters = 2;
1286 				op << "	${DO_WHILE_PRE}\n";
1287 				op << "	{\n";
1288 				op << "		res = coords; // ignore outer loop effect \n";
1289 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1290 				op << "		do\n";
1291 				op << "			res = res.yzwx + vec4(1.0);\n";
1292 				op << "		while (++j < ${TWO});\n";
1293 				op << "	} ${DO_WHILE_POST}\n";
1294 				break;
1295 
1296 			case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1297 				numIters = iterCount;
1298 				op << "	${DO_WHILE_PRE}\n";
1299 				op << "	{\n";
1300 				op << "		res = coords.wxyz - vec4(1.0);\n";
1301 				op << "		${COUNTER_PRECISION} int j = 0;\n";
1302 				op << "		while (j++ < ${TWO})\n";
1303 				op << "			res = res.yzwx + vec4(1.0);\n";
1304 				op << "		coords = res;\n";
1305 				op << "	} ${DO_WHILE_POST}\n";
1306 				break;
1307 
1308 			case LOOPCASE_PRE_FALLTHROUGH:
1309 				numIters = iterCount + 1;
1310 				op << "	int j = 3;\n";
1311 				op << "	switch (j)\n";
1312 				op << "	{\n";
1313 				op << "	case 3:\n";
1314 				op << "		res = res.yzwx + vec4(1.0);\n";
1315 				op << "	case 4:\n";
1316 				op << "		${DO_WHILE_PRE}\n";
1317 				op << "		{\n";
1318 				op << "			res = res.yzwx + vec4(1.0);\n";
1319 				op << "		} ${DO_WHILE_POST}\n";
1320 				op << "		break;\n";
1321 				op << "	}\n";
1322 				break;
1323 
1324 			case LOOPCASE_POST_FALLTHROUGH:
1325 				numIters = iterCount + 1;
1326 				op << "	int j = 3;\n";
1327 				op << "	switch (j)\n";
1328 				op << "	{\n";
1329 				op << "	case 3:\n";
1330 				op << "		${DO_WHILE_PRE}\n";
1331 				op << "		{\n";
1332 				op << "			res = res.yzwx + vec4(1.0);\n";
1333 				op << "		} ${DO_WHILE_POST}\n";
1334 				op << "	case 4:\n";
1335 				op << "		res = res.yzwx + vec4(1.0);\n";
1336 				op << "		break;\n";
1337 				op << "	}\n";
1338 				break;
1339 
1340 			case LOOPCASE_DOWHILE_TRAP:
1341 				numIters = iterCount = 3;
1342 				op << "	${DO_WHILE_PRE}\n";
1343 				op << "	{\n";
1344 				op << "		do\n";
1345 				op << "		{\n";
1346 				op << "			res = res.yzwx + vec4(1.0);\n";
1347 				op << "		} while (i >= ${THREE});\n";
1348 				op << "	} ${DO_WHILE_POST}\n";
1349 				break;
1350 
1351 			case LOOPCASE_IFBLOCK:
1352 				numIters = iterCount;
1353 				op << "	int j = 3;\n";
1354 				op << "	if (j == ${THREE})\n";
1355 				op << "	{\n";
1356 				op << "		${DO_WHILE_PRE}\n";
1357 				op << "		{\n";
1358 				op << "			res = res.yzwx + vec4(1.0);\n";
1359 				op << "		} ${DO_WHILE_POST}\n";
1360 				op << "	}\n";
1361 				op << "	else\n";
1362 				op << "	{\n";
1363 				op << "		res = res.yzwx + vec4(1.0);\n";
1364 				op << "	}\n";
1365 				break;
1366 
1367 			case LOOPCASE_ELSEBLOCK:
1368 				numIters = iterCount;
1369 				op << "	int j = 2;\n";
1370 				op << "	if (j == ${THREE})\n";
1371 				op << "	{\n";
1372 				op << "		res = res.yzwx + vec4(1.0);\n";
1373 				op << "	}\n";
1374 				op << "	else\n";
1375 				op << "	{\n";
1376 				op << "		${DO_WHILE_PRE}\n";
1377 				op << "		{\n";
1378 				op << "			res = res.yzwx + vec4(1.0);\n";
1379 				op << "		} ${DO_WHILE_POST}\n";
1380 				op << "	}\n";
1381 				break;
1382 
1383 			default:
1384 				DE_ASSERT(false);
1385 		}
1386 
1387 		doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1388 		if (loopCountType == LOOPCOUNT_CONSTANT)
1389 			doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1390 		else if (loopCountType == LOOPCOUNT_UNIFORM)
1391 			doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1392 		else if (loopCountType == LOOPCOUNT_DYNAMIC)
1393 			doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1394 		else
1395 			DE_ASSERT(false);
1396 	}
1397 
1398 	// Shader footers.
1399 	op << "	res -= vec4(${NUM_ITERS});\n";
1400 
1401 	if (isVertexCase)
1402 	{
1403 		vtx << "	v_color = res.rgb;\n";
1404 		frag << "	o_color = vec4(v_color.rgb, 1.0);\n";
1405 	}
1406 	else
1407 	{
1408 		vtx << "	v_coords = a_coords;\n";
1409 		frag << "	o_color = vec4(res.rgb, 1.0);\n";
1410 
1411 		if (loopCountType == LOOPCOUNT_DYNAMIC)
1412 			vtx << "	v_one = a_one;\n";
1413 	}
1414 
1415 	vtx << "}\n";
1416 	frag << "}\n";
1417 
1418 	// Constants.
1419 	std::string oneStr;
1420 	std::string twoStr;
1421 	std::string threeStr;
1422 	std::string iterCountStr;
1423 	std::string numItersStr;
1424 
1425 	numItersStr = de::toString(numIters);
1426 
1427 	if (loopCountType == LOOPCOUNT_CONSTANT)
1428 	{
1429 		oneStr			= "1";
1430 		twoStr			= "2";
1431 		threeStr		= "3";
1432 		iterCountStr	= de::toString(iterCount);
1433 	}
1434 	else if (loopCountType == LOOPCOUNT_UNIFORM)
1435 	{
1436 		oneStr			= "ui_one";
1437 		twoStr			= "ui_two";
1438 		threeStr		= "ui_three";
1439 		iterCountStr	= getIntUniformName(iterCount);
1440 	}
1441 	else if (loopCountType == LOOPCOUNT_DYNAMIC)
1442 	{
1443 		oneStr			= "one*ui_one";
1444 		twoStr			= "one*ui_two";
1445 		threeStr		= "one*ui_three";
1446 		iterCountStr	= std::string("one*") + getIntUniformName(iterCount);
1447 	}
1448 	else DE_ASSERT(false);
1449 
1450 	// Fill in shader templates.
1451 	std::map<std::string, std::string> params;
1452 	params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1453 	params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1454 	params.insert(std::pair<std::string, std::string>("NUM_ITERS", numItersStr));
1455 	params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1456 	params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1457 	params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1458 	params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1459 	params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1460 	params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1461 	params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1462 	params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1463 
1464 	tcu::StringTemplate vertTemplate(vtx.str());
1465 	tcu::StringTemplate fragTemplate(frag.str());
1466 	std::string vertexShaderSource = vertTemplate.specialize(params);
1467 	std::string fragmentShaderSource = fragTemplate.specialize(params);
1468 
1469 	// Create the case.
1470 	UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1471 	ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1472 	return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1473 }
1474 
1475 class ShaderLoopTests : public tcu::TestCaseGroup
1476 {
1477 public:
1478 							ShaderLoopTests			(tcu::TestContext& testCtx);
1479 	virtual					~ShaderLoopTests		(void);
1480 
1481 	virtual void			init					(void);
1482 
1483 private:
1484 							ShaderLoopTests			(const ShaderLoopTests&);		// not allowed!
1485 	ShaderLoopTests&		operator=				(const ShaderLoopTests&);		// not allowed!
1486 };
1487 
ShaderLoopTests(tcu::TestContext& testCtx)1488 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1489 		: TestCaseGroup(testCtx, "loops")
1490 {
1491 }
1492 
~ShaderLoopTests(void)1493 ShaderLoopTests::~ShaderLoopTests (void)
1494 {
1495 }
1496 
init(void)1497 void ShaderLoopTests::init (void)
1498 {
1499 	// Loop cases.
1500 
1501 	static const glu::ShaderType s_shaderTypes[] =
1502 	{
1503 		glu::SHADERTYPE_VERTEX,
1504 		glu::SHADERTYPE_FRAGMENT
1505 	};
1506 
1507 	static const glu::DataType s_countDataType[] =
1508 	{
1509 		glu::TYPE_INT,
1510 		glu::TYPE_FLOAT
1511 	};
1512 
1513 	TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic");
1514 	TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special");
1515 	addChild(genericGroup);
1516 	addChild(specialGroup);
1517 
1518 	for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1519 	{
1520 		const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1521 
1522 		for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1523 		{
1524 			const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1525 
1526 			std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1527 			std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1528 			TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str());
1529 			TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str());
1530 			genericGroup->addChild(genericSubGroup);
1531 			specialGroup->addChild(specialSubGroup);
1532 
1533 			// Generic cases.
1534 
1535 			for (int precision = glu::PRECISION_MEDIUMP; precision < glu::PRECISION_LAST; precision++)
1536 			{
1537 				const char* precisionName = getPrecisionName((glu::Precision)precision);
1538 
1539 				for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1540 				{
1541 					glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1542 					const char* dataTypeName = getDataTypeName(loopDataType);
1543 
1544 					for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1545 					{
1546 						glu::ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1547 						const char*	shaderTypeName	= getShaderTypeName(shaderType);
1548 						bool		isVertexCase	= (shaderType == glu::SHADERTYPE_VERTEX);
1549 
1550 						std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1551 						de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1552 						genericSubGroup->addChild(testCase.release());
1553 					}
1554 				}
1555 			}
1556 
1557 			// Special cases.
1558 
1559 			for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1560 			{
1561 				const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1562 
1563 				// no-iterations not possible with do-while.
1564 				if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1565 					continue;
1566 
1567 				for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1568 				{
1569 					glu::ShaderType	shaderType		= s_shaderTypes[shaderTypeNdx];
1570 					const char*	shaderTypeName	= getShaderTypeName(shaderType);
1571 					bool		isVertexCase	= (shaderType == glu::SHADERTYPE_VERTEX);
1572 
1573 					std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1574 					de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1575 					specialSubGroup->addChild(testCase.release());
1576 				}
1577 			}
1578 		}
1579 	}
1580 }
1581 
1582 } // anonymous
1583 
createLoopTests(tcu::TestContext& testCtx)1584 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1585 {
1586 	return new ShaderLoopTests(testCtx);
1587 }
1588 
1589 
1590 } // sr
1591 } // vkt
1592