Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Shader switch statement tests.
     22  *
     23  * Variables:
     24  *  + Selection expression type: static, uniform, dynamic
     25  *  + Switch layout - fall-through or use of default label
     26  *  + Switch nested in loop/conditional statement
     27  *  + Loop/conditional statement nested in switch
     28  *//*--------------------------------------------------------------------*/
     29 
     30 #include "es3fShaderSwitchTests.hpp"
     31 #include "glsShaderRenderCase.hpp"
     32 #include "glsShaderLibrary.hpp"
     33 #include "tcuStringTemplate.hpp"
     34 #include "deMath.h"
     35 
     36 namespace deqp
     37 {
     38 namespace gles3
     39 {
     40 namespace Functional
     41 {
     42 
     43 using namespace deqp::gls;
     44 using std::string;
     45 using std::map;
     46 using std::vector;
     47 
     48 class ShaderSwitchCase : public ShaderRenderCase
     49 {
     50 public:
     51 						ShaderSwitchCase			(Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc);
     52 	virtual				~ShaderSwitchCase			(void);
     53 };
     54 
     55 ShaderSwitchCase::ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc)
     56 	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
     57 {
     58 	m_vertShaderSource	= vtxSource;
     59 	m_fragShaderSource	= fragSource;
     60 }
     61 
     62 ShaderSwitchCase::~ShaderSwitchCase (void)
     63 {
     64 }
     65 
     66 enum SwitchType
     67 {
     68 	SWITCHTYPE_STATIC = 0,
     69 	SWITCHTYPE_UNIFORM,
     70 	SWITCHTYPE_DYNAMIC,
     71 
     72 	SWITCHTYPE_LAST
     73 };
     74 
     75 static void evalSwitchStatic	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	}
     76 static void evalSwitchUniform	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	}
     77 static void evalSwitchDynamic	(ShaderEvalContext& evalCtx)
     78 {
     79 	switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
     80 	{
     81 		case 0:		evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2);	break;
     82 		case 1:		evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1);	break;
     83 		case 2:		evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	break;
     84 		case 3:		evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0);	break;
     85 		default:	evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0);	break;
     86 	}
     87 }
     88 
     89 static tcu::TestCase* makeSwitchCase (Context& context, const char* name, const char* desc, SwitchType type, bool isVertex, const LineStream& switchBody)
     90 {
     91 	std::ostringstream	vtx;
     92 	std::ostringstream	frag;
     93 	std::ostringstream&	op		= isVertex ? vtx : frag;
     94 
     95 	vtx << "#version 300 es\n"
     96 		<< "in highp vec4 a_position;\n"
     97 		<< "in highp vec4 a_coords;\n";
     98 	frag << "#version 300 es\n"
     99 		 << "layout(location = 0) out mediump vec4 o_color;\n";
    100 
    101 	if (isVertex)
    102 	{
    103 		vtx << "out mediump vec4 v_color;\n";
    104 		frag << "in mediump vec4 v_color;\n";
    105 	}
    106 	else
    107 	{
    108 		vtx << "out highp vec4 v_coords;\n";
    109 		frag << "in highp vec4 v_coords;\n";
    110 	}
    111 
    112 	if (type == SWITCHTYPE_UNIFORM)
    113 		op << "uniform highp int ui_two;\n";
    114 
    115 	vtx << "\n"
    116 		<< "void main (void)\n"
    117 		<< "{\n"
    118 		<< "	gl_Position = a_position;\n";
    119 	frag << "\n"
    120 		 << "void main (void)\n"
    121 		 << "{\n";
    122 
    123 	// Setup.
    124 	op << "	highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
    125 	op << "	mediump vec3 res = vec3(0.0);\n\n";
    126 
    127 	// Switch body.
    128 	map<string, string> params;
    129 	params["CONDITION"] = type == SWITCHTYPE_STATIC		? "2"								:
    130 						  type == SWITCHTYPE_UNIFORM	? "ui_two"							:
    131 						  type == SWITCHTYPE_DYNAMIC	? "int(floor(coords.z*1.5 + 2.0))"	: "???";
    132 
    133 	op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
    134 	op << "\n";
    135 
    136 	if (isVertex)
    137 	{
    138 		vtx << "	v_color = vec4(res, 1.0);\n";
    139 		frag << "	o_color = v_color;\n";
    140 	}
    141 	else
    142 	{
    143 		vtx << "	v_coords = a_coords;\n";
    144 		frag << "	o_color = vec4(res, 1.0);\n";
    145 	}
    146 
    147 	vtx << "}\n";
    148 	frag << "}\n";
    149 
    150 	return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(),
    151 								type == SWITCHTYPE_STATIC	? evalSwitchStatic	:
    152 								type == SWITCHTYPE_UNIFORM	? evalSwitchUniform	:
    153 								type == SWITCHTYPE_DYNAMIC	? evalSwitchDynamic	: (ShaderEvalFunc)DE_NULL);
    154 }
    155 
    156 static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody)
    157 {
    158 	static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
    159 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
    160 
    161 	for (int type = 0; type < SWITCHTYPE_LAST; type++)
    162 	{
    163 		group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(),	desc, (SwitchType)type, true,	switchBody));
    164 		group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(),	desc, (SwitchType)type, false,	switchBody));
    165 	}
    166 }
    167 
    168 ShaderSwitchTests::ShaderSwitchTests (Context& context)
    169 	: TestCaseGroup(context, "switch", "Switch statement tests")
    170 {
    171 }
    172 
    173 ShaderSwitchTests::~ShaderSwitchTests (void)
    174 {
    175 }
    176 
    177 void ShaderSwitchTests::init (void)
    178 {
    179 	// Expected swizzles:
    180 	// 0: xyz
    181 	// 1: wzy
    182 	// 2: yzw
    183 	// 3: zyx
    184 
    185 	makeSwitchCases(this, "basic", "Basic switch statement usage",
    186 		LineStream(1)
    187 		<< "switch (${CONDITION})"
    188 		<< "{"
    189 		<< "	case 0:		res = coords.xyz;	break;"
    190 		<< "	case 1:		res = coords.wzy;	break;"
    191 		<< "	case 2:		res = coords.yzw;	break;"
    192 		<< "	case 3:		res = coords.zyx;	break;"
    193 		<< "}");
    194 
    195 	makeSwitchCases(this, "const_expr_in_label", "Constant expression in label",
    196 		LineStream(1)
    197 		<< "const int t = 2;"
    198 		<< "switch (${CONDITION})"
    199 		<< "{"
    200 		<< "	case int(0.0):	res = coords.xyz;	break;"
    201 		<< "	case 2-1:		res = coords.wzy;	break;"
    202 		<< "	case 3&(1<<1):	res = coords.yzw;	break;"
    203 		<< "	case t+1:		res = coords.zyx;	break;"
    204 		<< "}");
    205 
    206 	makeSwitchCases(this, "default_label", "Default label usage",
    207 		LineStream(1)
    208 		<< "switch (${CONDITION})"
    209 		<< "{"
    210 		<< "	case 0:		res = coords.xyz;	break;"
    211 		<< "	case 1:		res = coords.wzy;	break;"
    212 		<< "	case 3:		res = coords.zyx;	break;"
    213 		<< "	default:	res = coords.yzw;"
    214 		<< "}");
    215 
    216 	makeSwitchCases(this, "default_not_last", "Default label usage",
    217 		LineStream(1)
    218 		<< "switch (${CONDITION})"
    219 		<< "{"
    220 		<< "	case 0:		res = coords.xyz;	break;"
    221 		<< "	default:	res = coords.yzw;	break;"
    222 		<< "	case 1:		res = coords.wzy;	break;"
    223 		<< "	case 3:		res = coords.zyx;	break;"
    224 		<< "}");
    225 
    226 	makeSwitchCases(this, "no_default_label", "No match in switch without default label",
    227 		LineStream(1)
    228 		<< "res = coords.yzw;\n"
    229 		<< "switch (${CONDITION})"
    230 		<< "{"
    231 		<< "	case 0:		res = coords.xyz;	break;"
    232 		<< "	case 1:		res = coords.wzy;	break;"
    233 		<< "	case 3:		res = coords.zyx;	break;"
    234 		<< "}");
    235 
    236 	makeSwitchCases(this, "fall_through", "Fall-through",
    237 		LineStream(1)
    238 		<< "switch (${CONDITION})"
    239 		<< "{"
    240 		<< "	case 0:		res = coords.xyz;	break;"
    241 		<< "	case 1:		res = coords.wzy;	break;"
    242 		<< "	case 2:		coords = coords.yzwx;"
    243 		<< "	case 4:		res = vec3(coords);	break;"
    244 		<< "	case 3:		res = coords.zyx;	break;"
    245 		<< "}");
    246 
    247 	makeSwitchCases(this, "fall_through_default", "Fall-through",
    248 		LineStream(1)
    249 		<< "switch (${CONDITION})"
    250 		<< "{"
    251 		<< "	case 0:		res = coords.xyz;	break;"
    252 		<< "	case 1:		res = coords.wzy;	break;"
    253 		<< "	case 3:		res = coords.zyx;	break;"
    254 		<< "	case 2:		coords = coords.yzwx;"
    255 		<< "	default:	res = vec3(coords);"
    256 		<< "}");
    257 
    258 	makeSwitchCases(this, "conditional_fall_through", "Fall-through",
    259 		LineStream(1)
    260 		<< "highp vec4 tmp = coords;"
    261 		<< "switch (${CONDITION})"
    262 		<< "{"
    263 		<< "	case 0:		res = coords.xyz;	break;"
    264 		<< "	case 1:		res = coords.wzy;	break;"
    265 		<< "	case 2:"
    266 		<< "		tmp = coords.yzwx;"
    267 		<< "	case 3:"
    268 		<< "		res = vec3(tmp);"
    269 		<< "		if (${CONDITION} != 3)"
    270 		<< "			break;"
    271 		<< "	default:	res = tmp.zyx;		break;"
    272 		<< "}");
    273 
    274 	makeSwitchCases(this, "conditional_fall_through_2", "Fall-through",
    275 		LineStream(1)
    276 		<< "highp vec4 tmp = coords;"
    277 		<< "mediump int c = ${CONDITION};"
    278 		<< "switch (c)"
    279 		<< "{"
    280 		<< "	case 0:		res = coords.xyz;	break;"
    281 		<< "	case 1:		res = coords.wzy;	break;"
    282 		<< "	case 2:"
    283 		<< "		c += ${CONDITION};"
    284 		<< "		tmp = coords.yzwx;"
    285 		<< "	case 3:"
    286 		<< "		res = vec3(tmp);"
    287 		<< "		if (c == 4)"
    288 		<< "			break;"
    289 		<< "	default:	res = tmp.zyx;		break;"
    290 		<< "}");
    291 
    292 	makeSwitchCases(this, "scope", "Basic switch statement usage",
    293 		LineStream(1)
    294 		<< "switch (${CONDITION})"
    295 		<< "{"
    296 		<< "	case 0:		res = coords.xyz;	break;"
    297 		<< "	case 1:		res = coords.wzy;	break;"
    298 		<< "	case 2:"
    299 		<< "	{"
    300 		<< "		mediump vec3 t = coords.yzw;"
    301 		<< "		res = t;"
    302 		<< "		break;"
    303 		<< "	}"
    304 		<< "	case 3:		res = coords.zyx;	break;"
    305 		<< "}");
    306 
    307 	makeSwitchCases(this, "switch_in_if", "Switch in for loop",
    308 		LineStream(1)
    309 		<< "if (${CONDITION} >= 0)"
    310 		<< "{"
    311 		<< "	switch (${CONDITION})"
    312 		<< "	{"
    313 		<< "		case 0:		res = coords.xyz;	break;"
    314 		<< "		case 1:		res = coords.wzy;	break;"
    315 		<< "		case 2:		res = coords.yzw;	break;"
    316 		<< "		case 3:		res = coords.zyx;	break;"
    317 		<< "	}"
    318 		<< "}");
    319 
    320 	makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop",
    321 		LineStream(1)
    322 		<< "for (int i = 0; i <= ${CONDITION}; i++)"
    323 		<< "{"
    324 		<< "	switch (i)"
    325 		<< "	{"
    326 		<< "		case 0:		res = coords.xyz;	break;"
    327 		<< "		case 1:		res = coords.wzy;	break;"
    328 		<< "		case 2:		res = coords.yzw;	break;"
    329 		<< "		case 3:		res = coords.zyx;	break;"
    330 		<< "	}"
    331 		<< "}");
    332 
    333 	makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop",
    334 		LineStream(1)
    335 		<< "int i = 0;"
    336 		<< "while (i <= ${CONDITION})"
    337 		<< "{"
    338 		<< "	switch (i)"
    339 		<< "	{"
    340 		<< "		case 0:		res = coords.xyz;	break;"
    341 		<< "		case 1:		res = coords.wzy;	break;"
    342 		<< "		case 2:		res = coords.yzw;	break;"
    343 		<< "		case 3:		res = coords.zyx;	break;"
    344 		<< "	}"
    345 		<< "	i += 1;"
    346 		<< "}");
    347 
    348 	makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop",
    349 		LineStream(1)
    350 		<< "int i = 0;"
    351 		<< "do"
    352 		<< "{"
    353 		<< "	switch (i)"
    354 		<< "	{"
    355 		<< "		case 0:		res = coords.xyz;	break;"
    356 		<< "		case 1:		res = coords.wzy;	break;"
    357 		<< "		case 2:		res = coords.yzw;	break;"
    358 		<< "		case 3:		res = coords.zyx;	break;"
    359 		<< "	}"
    360 		<< "	i += 1;"
    361 		<< "} while (i <= ${CONDITION});");
    362 
    363 	makeSwitchCases(this, "if_in_switch", "Basic switch statement usage",
    364 		LineStream(1)
    365 		<< "switch (${CONDITION})"
    366 		<< "{"
    367 		<< "	case 0:		res = coords.xyz;	break;"
    368 		<< "	case 1:		res = coords.wzy;	break;"
    369 		<< "	default:"
    370 		<< "		if (${CONDITION} == 2)"
    371 		<< "			res = coords.yzw;"
    372 		<< "		else"
    373 		<< "			res = coords.zyx;"
    374 		<< "		break;"
    375 		<< "}");
    376 
    377 	makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage",
    378 		LineStream(1)
    379 		<< "switch (${CONDITION})"
    380 		<< "{"
    381 		<< "	case 0:		res = coords.xyz;	break;"
    382 		<< "	case 1:"
    383 		<< "	case 2:"
    384 		<< "	{"
    385 		<< "		highp vec3 t = coords.yzw;"
    386 		<< "		for (int i = 0; i < ${CONDITION}; i++)"
    387 		<< "			t = t.zyx;"
    388 		<< "		res = t;"
    389 		<< "		break;"
    390 		<< "	}"
    391 		<< "	default:	res = coords.zyx;	break;"
    392 		<< "}");
    393 
    394 	makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage",
    395 		LineStream(1)
    396 		<< "switch (${CONDITION})"
    397 		<< "{"
    398 		<< "	case 0:		res = coords.xyz;	break;"
    399 		<< "	case 1:"
    400 		<< "	case 2:"
    401 		<< "	{"
    402 		<< "		highp vec3 t = coords.yzw;"
    403 		<< "		int i = 0;"
    404 		<< "		while (i < ${CONDITION})"
    405 		<< "		{"
    406 		<< "			t = t.zyx;"
    407 		<< "			i += 1;"
    408 		<< "		}"
    409 		<< "		res = t;"
    410 		<< "		break;"
    411 		<< "	}"
    412 		<< "	default:	res = coords.zyx;	break;"
    413 		<< "}");
    414 
    415 	makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage",
    416 		LineStream(1)
    417 		<< "switch (${CONDITION})"
    418 		<< "{"
    419 		<< "	case 0:		res = coords.xyz;	break;"
    420 		<< "	case 1:"
    421 		<< "	case 2:"
    422 		<< "	{"
    423 		<< "		highp vec3 t = coords.yzw;"
    424 		<< "		int i = 0;"
    425 		<< "		do"
    426 		<< "		{"
    427 		<< "			t = t.zyx;"
    428 		<< "			i += 1;"
    429 		<< "		} while (i < ${CONDITION});"
    430 		<< "		res = t;"
    431 		<< "		break;"
    432 		<< "	}"
    433 		<< "	default:	res = coords.zyx;	break;"
    434 		<< "}");
    435 
    436 	makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage",
    437 		LineStream(1)
    438 		<< "switch (${CONDITION})"
    439 		<< "{"
    440 		<< "	case 0:		res = coords.xyz;	break;"
    441 		<< "	case 1:"
    442 		<< "	case 2:"
    443 		<< "		switch (${CONDITION} - 1)"
    444 		<< "		{"
    445 		<< "			case 0:		res = coords.wzy;	break;"
    446 		<< "			case 1:		res = coords.yzw;	break;"
    447 		<< "		}"
    448 		<< "		break;"
    449 		<< "	default:	res = coords.zyx;	break;"
    450 		<< "}");
    451 
    452 	// Negative cases.
    453 	ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
    454 	vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test");
    455 
    456 	for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
    457 		addChild(*i);
    458 }
    459 
    460 } // Functional
    461 } // gles3
    462 } // deqp
    463