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