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