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