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