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 36namespace deqp 37{ 38namespace gles3 39{ 40namespace Functional 41{ 42 43using namespace deqp::gls; 44using std::string; 45using std::map; 46using std::vector; 47 48class ShaderSwitchCase : public ShaderRenderCase 49{ 50public: 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 55ShaderSwitchCase::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 62ShaderSwitchCase::~ShaderSwitchCase (void) 63{ 64} 65 66enum SwitchType 67{ 68 SWITCHTYPE_STATIC = 0, 69 SWITCHTYPE_UNIFORM, 70 SWITCHTYPE_DYNAMIC, 71 72 SWITCHTYPE_LAST 73}; 74 75static void evalSwitchStatic (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); } 76static void evalSwitchUniform (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); } 77static 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 89static 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 156static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody, const bool skipDynamicType = false) 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 if (skipDynamicType && (type == SWITCHTYPE_DYNAMIC)) 164 continue; 165 166 group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(), desc, (SwitchType)type, true, switchBody)); 167 group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(), desc, (SwitchType)type, false, switchBody)); 168 } 169} 170 171ShaderSwitchTests::ShaderSwitchTests (Context& context) 172 : TestCaseGroup(context, "switch", "Switch statement tests") 173{ 174} 175 176ShaderSwitchTests::~ShaderSwitchTests (void) 177{ 178} 179 180void ShaderSwitchTests::init (void) 181{ 182 // Expected swizzles: 183 // 0: xyz 184 // 1: wzy 185 // 2: yzw 186 // 3: zyx 187 188 makeSwitchCases(this, "basic", "Basic switch statement usage", 189 LineStream(1) 190 << "switch (${CONDITION})" 191 << "{" 192 << " case 0: res = coords.xyz; break;" 193 << " case 1: res = coords.wzy; break;" 194 << " case 2: res = coords.yzw; break;" 195 << " case 3: res = coords.zyx; break;" 196 << "}"); 197 198 makeSwitchCases(this, "const_expr_in_label", "Constant expression in label", 199 LineStream(1) 200 << "const int t = 2;" 201 << "switch (${CONDITION})" 202 << "{" 203 << " case int(0.0): res = coords.xyz; break;" 204 << " case 2-1: res = coords.wzy; break;" 205 << " case 3&(1<<1): res = coords.yzw; break;" 206 << " case t+1: res = coords.zyx; break;" 207 << "}"); 208 209 makeSwitchCases(this, "default_label", "Default label usage", 210 LineStream(1) 211 << "switch (${CONDITION})" 212 << "{" 213 << " case 0: res = coords.xyz; break;" 214 << " case 1: res = coords.wzy; break;" 215 << " case 3: res = coords.zyx; break;" 216 << " default: res = coords.yzw;" 217 << "}"); 218 219 makeSwitchCases(this, "default_not_last", "Default label usage", 220 LineStream(1) 221 << "switch (${CONDITION})" 222 << "{" 223 << " case 0: res = coords.xyz; break;" 224 << " default: res = coords.yzw; break;" 225 << " case 1: res = coords.wzy; break;" 226 << " case 3: res = coords.zyx; break;" 227 << "}"); 228 229 makeSwitchCases(this, "no_default_label", "No match in switch without default label", 230 LineStream(1) 231 << "res = coords.yzw;\n" 232 << "switch (${CONDITION})" 233 << "{" 234 << " case 0: res = coords.xyz; break;" 235 << " case 1: res = coords.wzy; break;" 236 << " case 3: res = coords.zyx; break;" 237 << "}"); 238 239 makeSwitchCases(this, "default_only", "Default case only", 240 LineStream(1) 241 << "switch (${CONDITION})" 242 << "{" 243 << " default:" 244 << " res = coords.yzw;" 245 << "}", true); 246 247 makeSwitchCases(this, "empty_case_default", "Empty case and default", 248 LineStream(1) 249 << "switch (${CONDITION})" 250 << "{" 251 << " case 2:" 252 << " default:" 253 << " res = coords.yzw;" 254 << "}", true); 255 256 makeSwitchCases(this, "fall_through", "Fall-through", 257 LineStream(1) 258 << "switch (${CONDITION})" 259 << "{" 260 << " case 0: res = coords.xyz; break;" 261 << " case 1: res = coords.wzy; break;" 262 << " case 2: coords = coords.yzwx;" 263 << " case 4: res = vec3(coords); break;" 264 << " case 3: res = coords.zyx; break;" 265 << "}"); 266 267 makeSwitchCases(this, "fall_through_default", "Fall-through", 268 LineStream(1) 269 << "switch (${CONDITION})" 270 << "{" 271 << " case 0: res = coords.xyz; break;" 272 << " case 1: res = coords.wzy; break;" 273 << " case 3: res = coords.zyx; break;" 274 << " case 2: coords = coords.yzwx;" 275 << " default: res = vec3(coords);" 276 << "}"); 277 278 makeSwitchCases(this, "conditional_fall_through", "Fall-through", 279 LineStream(1) 280 << "highp vec4 tmp = coords;" 281 << "switch (${CONDITION})" 282 << "{" 283 << " case 0: res = coords.xyz; break;" 284 << " case 1: res = coords.wzy; break;" 285 << " case 2:" 286 << " tmp = coords.yzwx;" 287 << " case 3:" 288 << " res = vec3(tmp);" 289 << " if (${CONDITION} != 3)" 290 << " break;" 291 << " default: res = tmp.zyx; break;" 292 << "}"); 293 294 makeSwitchCases(this, "conditional_fall_through_2", "Fall-through", 295 LineStream(1) 296 << "highp vec4 tmp = coords;" 297 << "mediump int c = ${CONDITION};" 298 << "switch (c)" 299 << "{" 300 << " case 0: res = coords.xyz; break;" 301 << " case 1: res = coords.wzy; break;" 302 << " case 2:" 303 << " c += ${CONDITION};" 304 << " tmp = coords.yzwx;" 305 << " case 3:" 306 << " res = vec3(tmp);" 307 << " if (c == 4)" 308 << " break;" 309 << " default: res = tmp.zyx; break;" 310 << "}"); 311 312 makeSwitchCases(this, "scope", "Basic switch statement usage", 313 LineStream(1) 314 << "switch (${CONDITION})" 315 << "{" 316 << " case 0: res = coords.xyz; break;" 317 << " case 1: res = coords.wzy; break;" 318 << " case 2:" 319 << " {" 320 << " mediump vec3 t = coords.yzw;" 321 << " res = t;" 322 << " break;" 323 << " }" 324 << " case 3: res = coords.zyx; break;" 325 << "}"); 326 327 makeSwitchCases(this, "switch_in_if", "Switch in for loop", 328 LineStream(1) 329 << "if (${CONDITION} >= 0)" 330 << "{" 331 << " switch (${CONDITION})" 332 << " {" 333 << " case 0: res = coords.xyz; break;" 334 << " case 1: res = coords.wzy; break;" 335 << " case 2: res = coords.yzw; break;" 336 << " case 3: res = coords.zyx; break;" 337 << " }" 338 << "}"); 339 340 makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop", 341 LineStream(1) 342 << "for (int i = 0; i <= ${CONDITION}; i++)" 343 << "{" 344 << " switch (i)" 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(this, "switch_in_while_loop", "Switch in while loop", 354 LineStream(1) 355 << "int i = 0;" 356 << "while (i <= ${CONDITION})" 357 << "{" 358 << " switch (i)" 359 << " {" 360 << " case 0: res = coords.xyz; break;" 361 << " case 1: res = coords.wzy; break;" 362 << " case 2: res = coords.yzw; break;" 363 << " case 3: res = coords.zyx; break;" 364 << " }" 365 << " i += 1;" 366 << "}"); 367 368 makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop", 369 LineStream(1) 370 << "int i = 0;" 371 << "do" 372 << "{" 373 << " switch (i)" 374 << " {" 375 << " case 0: res = coords.xyz; break;" 376 << " case 1: res = coords.wzy; break;" 377 << " case 2: res = coords.yzw; break;" 378 << " case 3: res = coords.zyx; break;" 379 << " }" 380 << " i += 1;" 381 << "} while (i <= ${CONDITION});"); 382 383 makeSwitchCases(this, "if_in_switch", "Basic switch statement usage", 384 LineStream(1) 385 << "switch (${CONDITION})" 386 << "{" 387 << " case 0: res = coords.xyz; break;" 388 << " case 1: res = coords.wzy; break;" 389 << " default:" 390 << " if (${CONDITION} == 2)" 391 << " res = coords.yzw;" 392 << " else" 393 << " res = coords.zyx;" 394 << " break;" 395 << "}"); 396 397 makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage", 398 LineStream(1) 399 << "switch (${CONDITION})" 400 << "{" 401 << " case 0: res = coords.xyz; break;" 402 << " case 1:" 403 << " case 2:" 404 << " {" 405 << " highp vec3 t = coords.yzw;" 406 << " for (int i = 0; i < ${CONDITION}; i++)" 407 << " t = t.zyx;" 408 << " res = t;" 409 << " break;" 410 << " }" 411 << " default: res = coords.zyx; break;" 412 << "}"); 413 414 makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage", 415 LineStream(1) 416 << "switch (${CONDITION})" 417 << "{" 418 << " case 0: res = coords.xyz; break;" 419 << " case 1:" 420 << " case 2:" 421 << " {" 422 << " highp vec3 t = coords.yzw;" 423 << " int i = 0;" 424 << " while (i < ${CONDITION})" 425 << " {" 426 << " t = t.zyx;" 427 << " i += 1;" 428 << " }" 429 << " res = t;" 430 << " break;" 431 << " }" 432 << " default: res = coords.zyx; break;" 433 << "}"); 434 435 makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage", 436 LineStream(1) 437 << "switch (${CONDITION})" 438 << "{" 439 << " case 0: res = coords.xyz; break;" 440 << " case 1:" 441 << " case 2:" 442 << " {" 443 << " highp vec3 t = coords.yzw;" 444 << " int i = 0;" 445 << " do" 446 << " {" 447 << " t = t.zyx;" 448 << " i += 1;" 449 << " } while (i < ${CONDITION});" 450 << " res = t;" 451 << " break;" 452 << " }" 453 << " default: res = coords.zyx; break;" 454 << "}"); 455 456 makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage", 457 LineStream(1) 458 << "switch (${CONDITION})" 459 << "{" 460 << " case 0: res = coords.xyz; break;" 461 << " case 1:" 462 << " case 2:" 463 << " switch (${CONDITION} - 1)" 464 << " {" 465 << " case 0: res = coords.wzy; break;" 466 << " case 1: res = coords.yzw; break;" 467 << " }" 468 << " break;" 469 << " default: res = coords.zyx; break;" 470 << "}"); 471 472 // Negative cases. 473 ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo()); 474 vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test"); 475 476 for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++) 477 addChild(*i); 478} 479 480} // Functional 481} // gles3 482} // deqp 483