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