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