Home | History | Annotate | Download | only in shaderrender
      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 
     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 
     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 
     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 
     92 static void evalSwitchStatic	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
     93 static void evalSwitchUniform	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
     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 
    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);
    187 };
    188 
    189 ShaderSwitchTests::ShaderSwitchTests (tcu::TestContext& testCtx)
    190 	: tcu::TestCaseGroup (testCtx, "switch", "Switch statement tests")
    191 {
    192 }
    193 
    194 ShaderSwitchTests::~ShaderSwitchTests (void)
    195 {
    196 }
    197 
    198 void ShaderSwitchTests::makeSwitchCases (const string& name, const string& desc, const LineStream& switchBody)
    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 		addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_vertex"),	desc, (SwitchType)type, true,	switchBody).release());
    206 		addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_fragment"),	desc, (SwitchType)type, false,	switchBody).release());
    207 	}
    208 }
    209 
    210 void ShaderSwitchTests::init (void)
    211 {
    212 	// Expected swizzles:
    213 	// 0: xyz
    214 	// 1: wzy
    215 	// 2: yzw
    216 	// 3: zyx
    217 
    218 	makeSwitchCases("basic", "Basic switch statement usage",
    219 		LineStream(1)
    220 		<< "switch (${CONDITION})"
    221 		<< "{"
    222 		<< "	case 0:		res = coords.xyz;	break;"
    223 		<< "	case 1:		res = coords.wzy;	break;"
    224 		<< "	case 2:		res = coords.yzw;	break;"
    225 		<< "	case 3:		res = coords.zyx;	break;"
    226 		<< "}");
    227 
    228 	makeSwitchCases("const_expr_in_label", "Constant expression in label",
    229 		LineStream(1)
    230 		<< "const int t = 2;"
    231 		<< "switch (${CONDITION})"
    232 		<< "{"
    233 		<< "	case int(0.0):	res = coords.xyz;	break;"
    234 		<< "	case 2-1:		res = coords.wzy;	break;"
    235 		<< "	case 3&(1<<1):	res = coords.yzw;	break;"
    236 		<< "	case t+1:		res = coords.zyx;	break;"
    237 		<< "}");
    238 
    239 	makeSwitchCases("default_label", "Default label usage",
    240 		LineStream(1)
    241 		<< "switch (${CONDITION})"
    242 		<< "{"
    243 		<< "	case 0:		res = coords.xyz;	break;"
    244 		<< "	case 1:		res = coords.wzy;	break;"
    245 		<< "	case 3:		res = coords.zyx;	break;"
    246 		<< "	default:	res = coords.yzw;"
    247 		<< "}");
    248 
    249 	makeSwitchCases("default_not_last", "Default label usage",
    250 		LineStream(1)
    251 		<< "switch (${CONDITION})"
    252 		<< "{"
    253 		<< "	case 0:		res = coords.xyz;	break;"
    254 		<< "	default:	res = coords.yzw;	break;"
    255 		<< "	case 1:		res = coords.wzy;	break;"
    256 		<< "	case 3:		res = coords.zyx;	break;"
    257 		<< "}");
    258 
    259 	makeSwitchCases("no_default_label", "No match in switch without default label",
    260 		LineStream(1)
    261 		<< "res = coords.yzw;\n"
    262 		<< "switch (${CONDITION})"
    263 		<< "{"
    264 		<< "	case 0:		res = coords.xyz;	break;"
    265 		<< "	case 1:		res = coords.wzy;	break;"
    266 		<< "	case 3:		res = coords.zyx;	break;"
    267 		<< "}");
    268 
    269 	makeSwitchCases("fall_through", "Fall-through",
    270 		LineStream(1)
    271 		<< "switch (${CONDITION})"
    272 		<< "{"
    273 		<< "	case 0:		res = coords.xyz;	break;"
    274 		<< "	case 1:		res = coords.wzy;	break;"
    275 		<< "	case 2:		coords = coords.yzwx;"
    276 		<< "	case 4:		res = vec3(coords);	break;"
    277 		<< "	case 3:		res = coords.zyx;	break;"
    278 		<< "}");
    279 
    280 	makeSwitchCases("fall_through_default", "Fall-through",
    281 		LineStream(1)
    282 		<< "switch (${CONDITION})"
    283 		<< "{"
    284 		<< "	case 0:		res = coords.xyz;	break;"
    285 		<< "	case 1:		res = coords.wzy;	break;"
    286 		<< "	case 3:		res = coords.zyx;	break;"
    287 		<< "	case 2:		coords = coords.yzwx;"
    288 		<< "	default:	res = vec3(coords);"
    289 		<< "}");
    290 
    291 	makeSwitchCases("conditional_fall_through", "Fall-through",
    292 		LineStream(1)
    293 		<< "highp vec4 tmp = coords;"
    294 		<< "switch (${CONDITION})"
    295 		<< "{"
    296 		<< "	case 0:		res = coords.xyz;	break;"
    297 		<< "	case 1:		res = coords.wzy;	break;"
    298 		<< "	case 2:"
    299 		<< "		tmp = coords.yzwx;"
    300 		<< "	case 3:"
    301 		<< "		res = vec3(tmp);"
    302 		<< "		if (${CONDITION} != 3)"
    303 		<< "			break;"
    304 		<< "	default:	res = tmp.zyx;		break;"
    305 		<< "}");
    306 
    307 	makeSwitchCases("conditional_fall_through_2", "Fall-through",
    308 		LineStream(1)
    309 		<< "highp vec4 tmp = coords;"
    310 		<< "mediump int c = ${CONDITION};"
    311 		<< "switch (c)"
    312 		<< "{"
    313 		<< "	case 0:		res = coords.xyz;	break;"
    314 		<< "	case 1:		res = coords.wzy;	break;"
    315 		<< "	case 2:"
    316 		<< "		c += ${CONDITION};"
    317 		<< "		tmp = coords.yzwx;"
    318 		<< "	case 3:"
    319 		<< "		res = vec3(tmp);"
    320 		<< "		if (c == 4)"
    321 		<< "			break;"
    322 		<< "	default:	res = tmp.zyx;		break;"
    323 		<< "}");
    324 
    325 	makeSwitchCases("scope", "Basic switch statement usage",
    326 		LineStream(1)
    327 		<< "switch (${CONDITION})"
    328 		<< "{"
    329 		<< "	case 0:		res = coords.xyz;	break;"
    330 		<< "	case 1:		res = coords.wzy;	break;"
    331 		<< "	case 2:"
    332 		<< "	{"
    333 		<< "		mediump vec3 t = coords.yzw;"
    334 		<< "		res = t;"
    335 		<< "		break;"
    336 		<< "	}"
    337 		<< "	case 3:		res = coords.zyx;	break;"
    338 		<< "}");
    339 
    340 	makeSwitchCases("switch_in_if", "Switch in for loop",
    341 		LineStream(1)
    342 		<< "if (${CONDITION} >= 0)"
    343 		<< "{"
    344 		<< "	switch (${CONDITION})"
    345 		<< "	{"
    346 		<< "		case 0:		res = coords.xyz;	break;"
    347 		<< "		case 1:		res = coords.wzy;	break;"
    348 		<< "		case 2:		res = coords.yzw;	break;"
    349 		<< "		case 3:		res = coords.zyx;	break;"
    350 		<< "	}"
    351 		<< "}");
    352 
    353 	makeSwitchCases("switch_in_for_loop", "Switch in for loop",
    354 		LineStream(1)
    355 		<< "for (int i = 0; i <= ${CONDITION}; i++)"
    356 		<< "{"
    357 		<< "	switch (i)"
    358 		<< "	{"
    359 		<< "		case 0:		res = coords.xyz;	break;"
    360 		<< "		case 1:		res = coords.wzy;	break;"
    361 		<< "		case 2:		res = coords.yzw;	break;"
    362 		<< "		case 3:		res = coords.zyx;	break;"
    363 		<< "	}"
    364 		<< "}");
    365 
    366 
    367 	makeSwitchCases("switch_in_while_loop", "Switch in while loop",
    368 		LineStream(1)
    369 		<< "int i = 0;"
    370 		<< "while (i <= ${CONDITION})"
    371 		<< "{"
    372 		<< "	switch (i)"
    373 		<< "	{"
    374 		<< "		case 0:		res = coords.xyz;	break;"
    375 		<< "		case 1:		res = coords.wzy;	break;"
    376 		<< "		case 2:		res = coords.yzw;	break;"
    377 		<< "		case 3:		res = coords.zyx;	break;"
    378 		<< "	}"
    379 		<< "	i += 1;"
    380 		<< "}");
    381 
    382 	makeSwitchCases("switch_in_do_while_loop", "Switch in do-while loop",
    383 		LineStream(1)
    384 		<< "int i = 0;"
    385 		<< "do"
    386 		<< "{"
    387 		<< "	switch (i)"
    388 		<< "	{"
    389 		<< "		case 0:		res = coords.xyz;	break;"
    390 		<< "		case 1:		res = coords.wzy;	break;"
    391 		<< "		case 2:		res = coords.yzw;	break;"
    392 		<< "		case 3:		res = coords.zyx;	break;"
    393 		<< "	}"
    394 		<< "	i += 1;"
    395 		<< "} while (i <= ${CONDITION});");
    396 
    397 	makeSwitchCases("if_in_switch", "Basic switch statement usage",
    398 		LineStream(1)
    399 		<< "switch (${CONDITION})"
    400 		<< "{"
    401 		<< "	case 0:		res = coords.xyz;	break;"
    402 		<< "	case 1:		res = coords.wzy;	break;"
    403 		<< "	default:"
    404 		<< "		if (${CONDITION} == 2)"
    405 		<< "			res = coords.yzw;"
    406 		<< "		else"
    407 		<< "			res = coords.zyx;"
    408 		<< "		break;"
    409 		<< "}");
    410 
    411 	makeSwitchCases("for_loop_in_switch", "Basic switch statement usage",
    412 		LineStream(1)
    413 		<< "switch (${CONDITION})"
    414 		<< "{"
    415 		<< "	case 0:		res = coords.xyz;	break;"
    416 		<< "	case 1:"
    417 		<< "	case 2:"
    418 		<< "	{"
    419 		<< "		highp vec3 t = coords.yzw;"
    420 		<< "		for (int i = 0; i < ${CONDITION}; i++)"
    421 		<< "			t = t.zyx;"
    422 		<< "		res = t;"
    423 		<< "		break;"
    424 		<< "	}"
    425 		<< "	default:	res = coords.zyx;	break;"
    426 		<< "}");
    427 
    428 	makeSwitchCases("while_loop_in_switch", "Basic switch statement usage",
    429 		LineStream(1)
    430 		<< "switch (${CONDITION})"
    431 		<< "{"
    432 		<< "	case 0:		res = coords.xyz;	break;"
    433 		<< "	case 1:"
    434 		<< "	case 2:"
    435 		<< "	{"
    436 		<< "		highp vec3 t = coords.yzw;"
    437 		<< "		int i = 0;"
    438 		<< "		while (i < ${CONDITION})"
    439 		<< "		{"
    440 		<< "			t = t.zyx;"
    441 		<< "			i += 1;"
    442 		<< "		}"
    443 		<< "		res = t;"
    444 		<< "		break;"
    445 		<< "	}"
    446 		<< "	default:	res = coords.zyx;	break;"
    447 		<< "}");
    448 
    449 	makeSwitchCases("do_while_loop_in_switch", "Basic switch statement usage",
    450 		LineStream(1)
    451 		<< "switch (${CONDITION})"
    452 		<< "{"
    453 		<< "	case 0:		res = coords.xyz;	break;"
    454 		<< "	case 1:"
    455 		<< "	case 2:"
    456 		<< "	{"
    457 		<< "		highp vec3 t = coords.yzw;"
    458 		<< "		int i = 0;"
    459 		<< "		do"
    460 		<< "		{"
    461 		<< "			t = t.zyx;"
    462 		<< "			i += 1;"
    463 		<< "		} while (i < ${CONDITION});"
    464 		<< "		res = t;"
    465 		<< "		break;"
    466 		<< "	}"
    467 		<< "	default:	res = coords.zyx;	break;"
    468 		<< "}");
    469 
    470 	makeSwitchCases("switch_in_switch", "Basic switch statement usage",
    471 		LineStream(1)
    472 		<< "switch (${CONDITION})"
    473 		<< "{"
    474 		<< "	case 0:		res = coords.xyz;	break;"
    475 		<< "	case 1:"
    476 		<< "	case 2:"
    477 		<< "		switch (${CONDITION} - 1)"
    478 		<< "		{"
    479 		<< "			case 0:		res = coords.wzy;	break;"
    480 		<< "			case 1:		res = coords.yzw;	break;"
    481 		<< "		}"
    482 		<< "		break;"
    483 		<< "	default:	res = coords.zyx;	break;"
    484 		<< "}");
    485 }
    486 
    487 } // anonymous
    488 
    489 tcu::TestCaseGroup* createSwitchTests (tcu::TestContext& testCtx)
    490 {
    491 	return new ShaderSwitchTests(testCtx);
    492 }
    493 
    494 } // sr
    495 } // vkt
    496