• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 switch statement tests.
24  *
25  * Variables:
26  *  + Selection expression type: static, uniform, dynamic
27  *  + Switch layout - fall-through or use of default label
28  *  + Switch nested in loop/conditional statement
29  *  + Loop/conditional statement nested in switch
30  *//*--------------------------------------------------------------------*/
31 
32 #include "vktShaderRenderSwitchTests.hpp"
33 #include "vktShaderRender.hpp"
34 #include "tcuStringTemplate.hpp"
35 #include "deMath.h"
36 
37 namespace vkt
38 {
39 namespace sr
40 {
41 namespace
42 {
43 
setUniforms(ShaderRenderCaseInstance & instance,const tcu::Vec4 &)44 static void setUniforms(ShaderRenderCaseInstance& instance, const tcu::Vec4&)
45 {
46 	instance.useUniform(0u, UI_TWO);
47 }
48 
49 using std::string;
50 
51 class ShaderSwitchCase : public ShaderRenderCase
52 {
53 public:
54 						ShaderSwitchCase			(tcu::TestContext&	testCtx,
55 													 const string&		name,
56 													 bool				isVertexCase,
57 													 const string&		vtxSource,
58 													 const string&		fragSource,
59 													 ShaderEvalFunc		evalFunc,
60 													 UniformSetupFunc	setupUniformsFunc);
61 	virtual				~ShaderSwitchCase			(void);
62 };
63 
ShaderSwitchCase(tcu::TestContext & testCtx,const string & name,bool isVertexCase,const string & vtxSource,const string & fragSource,ShaderEvalFunc evalFunc,UniformSetupFunc setupUniformsFunc)64 ShaderSwitchCase::ShaderSwitchCase (tcu::TestContext&	testCtx,
65 									const string&		name,
66 									bool				isVertexCase,
67 									const string&		vtxSource,
68 									const string&		fragSource,
69 									ShaderEvalFunc		evalFunc,
70 									UniformSetupFunc	setupUniformsFunc)
71 	: ShaderRenderCase (testCtx, name, isVertexCase, evalFunc, new UniformSetup(setupUniformsFunc), DE_NULL)
72 {
73 	m_vertShaderSource	= vtxSource;
74 	m_fragShaderSource	= fragSource;
75 }
76 
~ShaderSwitchCase(void)77 ShaderSwitchCase::~ShaderSwitchCase (void)
78 {
79 }
80 
81 enum SwitchType
82 {
83 	SWITCHTYPE_STATIC = 0,
84 	SWITCHTYPE_UNIFORM,
85 	SWITCHTYPE_DYNAMIC,
86 
87 	SWITCHTYPE_LAST
88 };
89 
evalSwitchStatic(ShaderEvalContext & evalCtx)90 static void evalSwitchStatic	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
evalSwitchUniform(ShaderEvalContext & evalCtx)91 static void evalSwitchUniform	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
evalSwitchDynamic(ShaderEvalContext & evalCtx)92 static void evalSwitchDynamic	(ShaderEvalContext& evalCtx)
93 {
94 	switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
95 	{
96 		case 0:		evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2);	break;
97 		case 1:		evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1);	break;
98 		case 2:		evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	break;
99 		case 3:		evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0);	break;
100 		default:	evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0);	break;
101 	}
102 }
103 
makeSwitchCase(tcu::TestContext & testCtx,const string & name,SwitchType type,bool isVertex,const LineStream & switchBody)104 static de::MovePtr<ShaderSwitchCase> makeSwitchCase (tcu::TestContext& testCtx, const string& name, SwitchType type, bool isVertex, const LineStream& switchBody)
105 {
106 	std::ostringstream	vtx;
107 	std::ostringstream	frag;
108 	std::ostringstream&	op		= isVertex ? vtx : frag;
109 
110 	vtx << "#version 310 es\n"
111 		<< "layout(location = 0) in highp vec4 a_position;\n"
112 		<< "layout(location = 1) in highp vec4 a_coords;\n\n";
113 	frag	<< "#version 310 es\n"
114 			<< "layout(location = 0) out mediump vec4 o_color;\n";
115 
116 	if (isVertex)
117 	{
118 		vtx << "layout(location = 0) out mediump vec4 v_color;\n";
119 		frag << "layout(location = 0) in mediump vec4 v_color;\n";
120 	}
121 	else
122 	{
123 		vtx << "layout(location = 0) out highp vec4 v_coords;\n";
124 		frag << "layout(location = 0) in highp vec4 v_coords;\n";
125 	}
126 
127 	if (type == SWITCHTYPE_UNIFORM)
128 		op << "layout (std140, set=0, binding=0) uniform buffer0 { highp int ui_two; };\n";
129 
130 	vtx << "\n"
131 		<< "void main (void)\n"
132 		<< "{\n"
133 		<< "	gl_Position = a_position;\n";
134 	frag << "\n"
135 		 << "void main (void)\n"
136 		 << "{\n";
137 
138 	// Setup.
139 	op << "	highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
140 	op << "	mediump vec3 res = vec3(0.0);\n\n";
141 
142 	// Switch body.
143 	std::map<string, string> params;
144 	params["CONDITION"] = type == SWITCHTYPE_STATIC		? "2"								:
145 						  type == SWITCHTYPE_UNIFORM	? "ui_two"							:
146 						  type == SWITCHTYPE_DYNAMIC	? "int(floor(coords.z*1.5 + 2.0))"	: "???";
147 
148 	op << tcu::StringTemplate(switchBody.str()).specialize(params);
149 	op << "\n";
150 
151 	if (isVertex)
152 	{
153 		vtx << "	v_color = vec4(res, 1.0);\n";
154 		frag << "	o_color = v_color;\n";
155 	}
156 	else
157 	{
158 		vtx << "	v_coords = a_coords;\n";
159 		frag << "	o_color = vec4(res, 1.0);\n";
160 	}
161 
162 	vtx << "}\n";
163 	frag << "}\n";
164 
165 	return de::MovePtr<ShaderSwitchCase>(new ShaderSwitchCase(testCtx, name, isVertex, vtx.str(), frag.str(),
166 															type == SWITCHTYPE_STATIC	? evalSwitchStatic	:
167 															type == SWITCHTYPE_UNIFORM	? evalSwitchUniform	:
168 															type == SWITCHTYPE_DYNAMIC	? evalSwitchDynamic	: (ShaderEvalFunc)DE_NULL,
169 															type == SWITCHTYPE_UNIFORM	? setUniforms : DE_NULL));
170 }
171 
172 class ShaderSwitchTests : public tcu::TestCaseGroup
173 {
174 public:
175 							ShaderSwitchTests		(tcu::TestContext& context);
176 	virtual					~ShaderSwitchTests		(void);
177 
178 	virtual void			init					(void);
179 
180 private:
181 							ShaderSwitchTests		(const ShaderSwitchTests&);		// not allowed!
182 	ShaderSwitchTests&		operator=				(const ShaderSwitchTests&);		// not allowed!
183 
184 	void					makeSwitchCases			(const string& name, const LineStream& switchBody, const bool skipDynamicType = false);
185 };
186 
ShaderSwitchTests(tcu::TestContext & testCtx)187 ShaderSwitchTests::ShaderSwitchTests (tcu::TestContext& testCtx)
188 	: tcu::TestCaseGroup (testCtx, "switch")
189 {
190 }
191 
~ShaderSwitchTests(void)192 ShaderSwitchTests::~ShaderSwitchTests (void)
193 {
194 }
195 
makeSwitchCases(const string & name,const LineStream & switchBody,const bool skipDynamicType)196 void ShaderSwitchTests::makeSwitchCases (const string& name, const LineStream& switchBody, const bool skipDynamicType)
197 {
198 	static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
199 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
200 
201 	for (int type = 0; type < SWITCHTYPE_LAST; type++)
202 	{
203 		if (skipDynamicType && (type == SWITCHTYPE_DYNAMIC))
204 			continue;
205 
206 		addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_vertex"), (SwitchType)type, true,	switchBody).release());
207 		addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_fragment"), (SwitchType)type, false,	switchBody).release());
208 	}
209 }
210 
init(void)211 void ShaderSwitchTests::init (void)
212 {
213 	// Expected swizzles:
214 	// 0: xyz
215 	// 1: wzy
216 	// 2: yzw
217 	// 3: zyx
218 
219 	// Basic switch statement usage
220 	makeSwitchCases("basic",
221 		LineStream(1)
222 		<< "switch (${CONDITION})"
223 		<< "{"
224 		<< "	case 0:		res = coords.xyz;	break;"
225 		<< "	case 1:		res = coords.wzy;	break;"
226 		<< "	case 2:		res = coords.yzw;	break;"
227 		<< "	case 3:		res = coords.zyx;	break;"
228 		<< "}");
229 
230 	// Constant expression in label
231 	makeSwitchCases("const_expr_in_label",
232 		LineStream(1)
233 		<< "const int t = 2;"
234 		<< "switch (${CONDITION})"
235 		<< "{"
236 		<< "	case int(0.0):	res = coords.xyz;	break;"
237 		<< "	case 2-1:		res = coords.wzy;	break;"
238 		<< "	case 3&(1<<1):	res = coords.yzw;	break;"
239 		<< "	case t+1:		res = coords.zyx;	break;"
240 		<< "}");
241 
242 	// Default label usage
243 	makeSwitchCases("default_label",
244 		LineStream(1)
245 		<< "switch (${CONDITION})"
246 		<< "{"
247 		<< "	case 0:		res = coords.xyz;	break;"
248 		<< "	case 1:		res = coords.wzy;	break;"
249 		<< "	case 3:		res = coords.zyx;	break;"
250 		<< "	default:	res = coords.yzw;"
251 		<< "}");
252 
253 	// Default label usage
254 	makeSwitchCases("default_not_last",
255 		LineStream(1)
256 		<< "switch (${CONDITION})"
257 		<< "{"
258 		<< "	case 0:		res = coords.xyz;	break;"
259 		<< "	default:	res = coords.yzw;	break;"
260 		<< "	case 1:		res = coords.wzy;	break;"
261 		<< "	case 3:		res = coords.zyx;	break;"
262 		<< "}");
263 
264 	// No match in switch without default label
265 	makeSwitchCases("no_default_label",
266 		LineStream(1)
267 		<< "res = coords.yzw;\n"
268 		<< "switch (${CONDITION})"
269 		<< "{"
270 		<< "	case 0:		res = coords.xyz;	break;"
271 		<< "	case 1:		res = coords.wzy;	break;"
272 		<< "	case 3:		res = coords.zyx;	break;"
273 		<< "}");
274 
275 	// Default case only
276 	makeSwitchCases("default_only",
277 		LineStream(1)
278 		<< "switch (${CONDITION})"
279 		<< "{"
280 		<< "	default:"
281 		<< "		res = coords.yzw;"
282 		<< "}", true);
283 
284 	// Empty case and default
285 	makeSwitchCases("empty_case_default",
286 		LineStream(1)
287 		<< "switch (${CONDITION})"
288 		<< "{"
289 		<< "	case 2:"
290 		<< "	default:"
291 		<< "		res = coords.yzw;"
292 		<< "}", true);
293 
294 	// Fall-through
295 	makeSwitchCases("fall_through",
296 		LineStream(1)
297 		<< "switch (${CONDITION})"
298 		<< "{"
299 		<< "	case 0:		res = coords.xyz;	break;"
300 		<< "	case 1:		res = coords.wzy;	break;"
301 		<< "	case 2:		coords = coords.yzwx;"
302 		<< "	case 4:		res = vec3(coords);	break;"
303 		<< "	case 3:		res = coords.zyx;	break;"
304 		<< "}");
305 
306 	// Fall-through
307 	makeSwitchCases("fall_through_default",
308 		LineStream(1)
309 		<< "switch (${CONDITION})"
310 		<< "{"
311 		<< "	case 0:		res = coords.xyz;	break;"
312 		<< "	case 1:		res = coords.wzy;	break;"
313 		<< "	case 3:		res = coords.zyx;	break;"
314 		<< "	case 2:		coords = coords.yzwx;"
315 		<< "	default:	res = vec3(coords);"
316 		<< "}");
317 
318 	// Fall-through
319 	makeSwitchCases("conditional_fall_through",
320 		LineStream(1)
321 		<< "highp vec4 tmp = coords;"
322 		<< "switch (${CONDITION})"
323 		<< "{"
324 		<< "	case 0:		res = coords.xyz;	break;"
325 		<< "	case 1:		res = coords.wzy;	break;"
326 		<< "	case 2:"
327 		<< "		tmp = coords.yzwx;"
328 		<< "	case 3:"
329 		<< "		res = vec3(tmp);"
330 		<< "		if (${CONDITION} != 3)"
331 		<< "			break;"
332 		<< "	default:	res = tmp.zyx;		break;"
333 		<< "}");
334 
335 	// Fall-through
336 	makeSwitchCases("conditional_fall_through_2",
337 		LineStream(1)
338 		<< "highp vec4 tmp = coords;"
339 		<< "mediump int c = ${CONDITION};"
340 		<< "switch (c)"
341 		<< "{"
342 		<< "	case 0:		res = coords.xyz;	break;"
343 		<< "	case 1:		res = coords.wzy;	break;"
344 		<< "	case 2:"
345 		<< "		c += ${CONDITION};"
346 		<< "		tmp = coords.yzwx;"
347 		<< "	case 3:"
348 		<< "		res = vec3(tmp);"
349 		<< "		if (c == 4)"
350 		<< "			break;"
351 		<< "	default:	res = tmp.zyx;		break;"
352 		<< "}");
353 
354 	// Basic switch statement usage
355 	makeSwitchCases("scope",
356 		LineStream(1)
357 		<< "switch (${CONDITION})"
358 		<< "{"
359 		<< "	case 0:		res = coords.xyz;	break;"
360 		<< "	case 1:		res = coords.wzy;	break;"
361 		<< "	case 2:"
362 		<< "	{"
363 		<< "		mediump vec3 t = coords.yzw;"
364 		<< "		res = t;"
365 		<< "		break;"
366 		<< "	}"
367 		<< "	case 3:		res = coords.zyx;	break;"
368 		<< "}");
369 
370 	// Switch in for loop
371 	makeSwitchCases("switch_in_if",
372 		LineStream(1)
373 		<< "if (${CONDITION} >= 0)"
374 		<< "{"
375 		<< "	switch (${CONDITION})"
376 		<< "	{"
377 		<< "		case 0:		res = coords.xyz;	break;"
378 		<< "		case 1:		res = coords.wzy;	break;"
379 		<< "		case 2:		res = coords.yzw;	break;"
380 		<< "		case 3:		res = coords.zyx;	break;"
381 		<< "	}"
382 		<< "}");
383 
384 	// Switch in for loop
385 	makeSwitchCases("switch_in_for_loop",
386 		LineStream(1)
387 		<< "for (int i = 0; i <= ${CONDITION}; i++)"
388 		<< "{"
389 		<< "	switch (i)"
390 		<< "	{"
391 		<< "		case 0:		res = coords.xyz;	break;"
392 		<< "		case 1:		res = coords.wzy;	break;"
393 		<< "		case 2:		res = coords.yzw;	break;"
394 		<< "		case 3:		res = coords.zyx;	break;"
395 		<< "	}"
396 		<< "}");
397 
398 
399 	// Switch in while loop
400 	makeSwitchCases("switch_in_while_loop",
401 		LineStream(1)
402 		<< "int i = 0;"
403 		<< "while (i <= ${CONDITION})"
404 		<< "{"
405 		<< "	switch (i)"
406 		<< "	{"
407 		<< "		case 0:		res = coords.xyz;	break;"
408 		<< "		case 1:		res = coords.wzy;	break;"
409 		<< "		case 2:		res = coords.yzw;	break;"
410 		<< "		case 3:		res = coords.zyx;	break;"
411 		<< "	}"
412 		<< "	i += 1;"
413 		<< "}");
414 
415 	// Switch in do-while loop
416 	makeSwitchCases("switch_in_do_while_loop",
417 		LineStream(1)
418 		<< "int i = 0;"
419 		<< "do"
420 		<< "{"
421 		<< "	switch (i)"
422 		<< "	{"
423 		<< "		case 0:		res = coords.xyz;	break;"
424 		<< "		case 1:		res = coords.wzy;	break;"
425 		<< "		case 2:		res = coords.yzw;	break;"
426 		<< "		case 3:		res = coords.zyx;	break;"
427 		<< "	}"
428 		<< "	i += 1;"
429 		<< "} while (i <= ${CONDITION});");
430 
431 	// Basic switch statement usage
432 	makeSwitchCases("if_in_switch",
433 		LineStream(1)
434 		<< "switch (${CONDITION})"
435 		<< "{"
436 		<< "	case 0:		res = coords.xyz;	break;"
437 		<< "	case 1:		res = coords.wzy;	break;"
438 		<< "	default:"
439 		<< "		if (${CONDITION} == 2)"
440 		<< "			res = coords.yzw;"
441 		<< "		else"
442 		<< "			res = coords.zyx;"
443 		<< "		break;"
444 		<< "}");
445 
446 	// Basic switch statement usage
447 	makeSwitchCases("for_loop_in_switch",
448 		LineStream(1)
449 		<< "switch (${CONDITION})"
450 		<< "{"
451 		<< "	case 0:		res = coords.xyz;	break;"
452 		<< "	case 1:"
453 		<< "	case 2:"
454 		<< "	{"
455 		<< "		highp vec3 t = coords.yzw;"
456 		<< "		for (int i = 0; i < ${CONDITION}; i++)"
457 		<< "			t = t.zyx;"
458 		<< "		res = t;"
459 		<< "		break;"
460 		<< "	}"
461 		<< "	default:	res = coords.zyx;	break;"
462 		<< "}");
463 
464 	// Basic switch statement usage
465 	makeSwitchCases("while_loop_in_switch",
466 		LineStream(1)
467 		<< "switch (${CONDITION})"
468 		<< "{"
469 		<< "	case 0:		res = coords.xyz;	break;"
470 		<< "	case 1:"
471 		<< "	case 2:"
472 		<< "	{"
473 		<< "		highp vec3 t = coords.yzw;"
474 		<< "		int i = 0;"
475 		<< "		while (i < ${CONDITION})"
476 		<< "		{"
477 		<< "			t = t.zyx;"
478 		<< "			i += 1;"
479 		<< "		}"
480 		<< "		res = t;"
481 		<< "		break;"
482 		<< "	}"
483 		<< "	default:	res = coords.zyx;	break;"
484 		<< "}");
485 
486 	// Basic switch statement usage
487 	makeSwitchCases("do_while_loop_in_switch",
488 		LineStream(1)
489 		<< "switch (${CONDITION})"
490 		<< "{"
491 		<< "	case 0:		res = coords.xyz;	break;"
492 		<< "	case 1:"
493 		<< "	case 2:"
494 		<< "	{"
495 		<< "		highp vec3 t = coords.yzw;"
496 		<< "		int i = 0;"
497 		<< "		do"
498 		<< "		{"
499 		<< "			t = t.zyx;"
500 		<< "			i += 1;"
501 		<< "		} while (i < ${CONDITION});"
502 		<< "		res = t;"
503 		<< "		break;"
504 		<< "	}"
505 		<< "	default:	res = coords.zyx;	break;"
506 		<< "}");
507 
508 	// Basic switch statement usage
509 	makeSwitchCases("switch_in_switch",
510 		LineStream(1)
511 		<< "switch (${CONDITION})"
512 		<< "{"
513 		<< "	case 0:		res = coords.xyz;	break;"
514 		<< "	case 1:"
515 		<< "	case 2:"
516 		<< "		switch (${CONDITION} - 1)"
517 		<< "		{"
518 		<< "			case 0:		res = coords.wzy;	break;"
519 		<< "			case 1:		res = coords.yzw;	break;"
520 		<< "		}"
521 		<< "		break;"
522 		<< "	default:	res = coords.zyx;	break;"
523 		<< "}");
524 }
525 
526 } // anonymous
527 
createSwitchTests(tcu::TestContext & testCtx)528 tcu::TestCaseGroup* createSwitchTests (tcu::TestContext& testCtx)
529 {
530 	return new ShaderSwitchTests(testCtx);
531 }
532 
533 } // sr
534 } // vkt
535