1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "compiler/OutputGLSL.h" 8 #include "compiler/debug.h" 9 10 namespace 11 { 12 TString getTypeName(const TType& type) 13 { 14 TInfoSinkBase out; 15 if (type.isMatrix()) 16 { 17 out << "mat"; 18 out << type.getNominalSize(); 19 } 20 else if (type.isVector()) 21 { 22 switch (type.getBasicType()) 23 { 24 case EbtFloat: out << "vec"; break; 25 case EbtInt: out << "ivec"; break; 26 case EbtBool: out << "bvec"; break; 27 default: UNREACHABLE(); break; 28 } 29 out << type.getNominalSize(); 30 } 31 else 32 { 33 if (type.getBasicType() == EbtStruct) 34 out << type.getTypeName(); 35 else 36 out << type.getBasicString(); 37 } 38 return TString(out.c_str()); 39 } 40 41 TString arrayBrackets(const TType& type) 42 { 43 ASSERT(type.isArray()); 44 TInfoSinkBase out; 45 out << "[" << type.getArraySize() << "]"; 46 return TString(out.c_str()); 47 } 48 49 bool isSingleStatement(TIntermNode* node) { 50 if (const TIntermAggregate* aggregate = node->getAsAggregate()) 51 { 52 return (aggregate->getOp() != EOpFunction) && 53 (aggregate->getOp() != EOpSequence); 54 } 55 else if (const TIntermSelection* selection = node->getAsSelectionNode()) 56 { 57 // Ternary operators are usually part of an assignment operator. 58 // This handles those rare cases in which they are all by themselves. 59 return selection->usesTernaryOperator(); 60 } 61 else if (node->getAsLoopNode()) 62 { 63 return false; 64 } 65 return true; 66 } 67 } // namespace 68 69 TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink) 70 : TIntermTraverser(true, true, true), 71 mObjSink(objSink), 72 mDeclaringVariables(false) 73 { 74 } 75 76 void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr) 77 { 78 TInfoSinkBase& out = objSink(); 79 if (visit == PreVisit && preStr) 80 { 81 out << preStr; 82 } 83 else if (visit == InVisit && inStr) 84 { 85 out << inStr; 86 } 87 else if (visit == PostVisit && postStr) 88 { 89 out << postStr; 90 } 91 } 92 93 void TOutputGLSL::writeVariableType(const TType& type) 94 { 95 TInfoSinkBase& out = objSink(); 96 TQualifier qualifier = type.getQualifier(); 97 // TODO(alokp): Validate qualifier for variable declarations. 98 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) 99 out << type.getQualifierString() << " "; 100 101 // Declare the struct if we have not done so already. 102 if ((type.getBasicType() == EbtStruct) && 103 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end())) 104 { 105 out << "struct " << type.getTypeName() << "{\n"; 106 const TTypeList* structure = type.getStruct(); 107 ASSERT(structure != NULL); 108 for (size_t i = 0; i < structure->size(); ++i) 109 { 110 const TType* fieldType = (*structure)[i].type; 111 ASSERT(fieldType != NULL); 112 out << getTypeName(*fieldType) << " " << fieldType->getFieldName(); 113 if (fieldType->isArray()) 114 out << arrayBrackets(*fieldType); 115 out << ";\n"; 116 } 117 out << "}"; 118 mDeclaredStructs.insert(type.getTypeName()); 119 } 120 else 121 { 122 out << getTypeName(type); 123 } 124 } 125 126 void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args) 127 { 128 TInfoSinkBase& out = objSink(); 129 for (TIntermSequence::const_iterator iter = args.begin(); 130 iter != args.end(); ++iter) 131 { 132 const TIntermSymbol* arg = (*iter)->getAsSymbolNode(); 133 ASSERT(arg != NULL); 134 135 const TType& type = arg->getType(); 136 TQualifier qualifier = type.getQualifier(); 137 // TODO(alokp): Validate qualifier for function arguments. 138 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) 139 out << type.getQualifierString() << " "; 140 141 out << getTypeName(type); 142 143 const TString& name = arg->getSymbol(); 144 if (!name.empty()) 145 out << " " << name; 146 if (type.isArray()) 147 out << arrayBrackets(type); 148 149 // Put a comma if this is not the last argument. 150 if (iter != args.end() - 1) 151 out << ", "; 152 } 153 } 154 155 const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type, 156 const ConstantUnion* pConstUnion) 157 { 158 TInfoSinkBase& out = objSink(); 159 160 if (type.getBasicType() == EbtStruct) 161 { 162 out << type.getTypeName() << "("; 163 const TTypeList* structure = type.getStruct(); 164 ASSERT(structure != NULL); 165 for (size_t i = 0; i < structure->size(); ++i) 166 { 167 const TType* fieldType = (*structure)[i].type; 168 ASSERT(fieldType != NULL); 169 pConstUnion = writeConstantUnion(*fieldType, pConstUnion); 170 if (i != structure->size() - 1) out << ", "; 171 } 172 out << ")"; 173 } 174 else 175 { 176 int size = type.getObjectSize(); 177 bool writeType = size > 1; 178 if (writeType) out << getTypeName(type) << "("; 179 for (int i = 0; i < size; ++i, ++pConstUnion) 180 { 181 switch (pConstUnion->getType()) 182 { 183 case EbtFloat: out << pConstUnion->getFConst(); break; 184 case EbtInt: out << pConstUnion->getIConst(); break; 185 case EbtBool: out << pConstUnion->getBConst(); break; 186 default: UNREACHABLE(); 187 } 188 if (i != size - 1) out << ", "; 189 } 190 if (writeType) out << ")"; 191 } 192 return pConstUnion; 193 } 194 195 void TOutputGLSL::visitSymbol(TIntermSymbol* node) 196 { 197 TInfoSinkBase& out = objSink(); 198 out << node->getSymbol(); 199 200 if (mDeclaringVariables && node->getType().isArray()) 201 out << arrayBrackets(node->getType()); 202 } 203 204 void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node) 205 { 206 writeConstantUnion(node->getType(), node->getUnionArrayPointer()); 207 } 208 209 bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node) 210 { 211 bool visitChildren = true; 212 TInfoSinkBase& out = objSink(); 213 switch (node->getOp()) 214 { 215 case EOpInitialize: 216 if (visit == InVisit) 217 { 218 out << " = "; 219 // RHS of initialize is not being declared. 220 mDeclaringVariables = false; 221 } 222 break; 223 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; 224 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; 225 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; 226 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; 227 // Notice the fall-through. 228 case EOpMulAssign: 229 case EOpVectorTimesMatrixAssign: 230 case EOpVectorTimesScalarAssign: 231 case EOpMatrixTimesScalarAssign: 232 case EOpMatrixTimesMatrixAssign: 233 writeTriplet(visit, "(", " *= ", ")"); 234 break; 235 236 case EOpIndexDirect: 237 case EOpIndexIndirect: 238 writeTriplet(visit, NULL, "[", "]"); 239 break; 240 case EOpIndexDirectStruct: 241 if (visit == InVisit) 242 { 243 out << "."; 244 // TODO(alokp): ASSERT 245 out << node->getType().getFieldName(); 246 visitChildren = false; 247 } 248 break; 249 case EOpVectorSwizzle: 250 if (visit == InVisit) 251 { 252 out << "."; 253 TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); 254 TIntermSequence& sequence = rightChild->getSequence(); 255 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) 256 { 257 TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); 258 ASSERT(element->getBasicType() == EbtInt); 259 ASSERT(element->getNominalSize() == 1); 260 const ConstantUnion& data = element->getUnionArrayPointer()[0]; 261 ASSERT(data.getType() == EbtInt); 262 switch (data.getIConst()) 263 { 264 case 0: out << "x"; break; 265 case 1: out << "y"; break; 266 case 2: out << "z"; break; 267 case 3: out << "w"; break; 268 default: UNREACHABLE(); break; 269 } 270 } 271 visitChildren = false; 272 } 273 break; 274 275 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; 276 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; 277 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; 278 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; 279 case EOpMod: UNIMPLEMENTED(); break; 280 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; 281 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; 282 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; 283 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; 284 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; 285 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; 286 287 // Notice the fall-through. 288 case EOpVectorTimesScalar: 289 case EOpVectorTimesMatrix: 290 case EOpMatrixTimesVector: 291 case EOpMatrixTimesScalar: 292 case EOpMatrixTimesMatrix: 293 writeTriplet(visit, "(", " * ", ")"); 294 break; 295 296 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; 297 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; 298 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; 299 default: UNREACHABLE(); break; 300 } 301 302 return visitChildren; 303 } 304 305 bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node) 306 { 307 switch (node->getOp()) 308 { 309 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break; 310 case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break; 311 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break; 312 313 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break; 314 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break; 315 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break; 316 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break; 317 318 case EOpConvIntToBool: 319 case EOpConvFloatToBool: 320 switch (node->getOperand()->getType().getNominalSize()) 321 { 322 case 1: writeTriplet(visit, "bool(", NULL, ")"); break; 323 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break; 324 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break; 325 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break; 326 default: UNREACHABLE(); 327 } 328 break; 329 case EOpConvBoolToFloat: 330 case EOpConvIntToFloat: 331 switch (node->getOperand()->getType().getNominalSize()) 332 { 333 case 1: writeTriplet(visit, "float(", NULL, ")"); break; 334 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break; 335 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break; 336 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break; 337 default: UNREACHABLE(); 338 } 339 break; 340 case EOpConvFloatToInt: 341 case EOpConvBoolToInt: 342 switch (node->getOperand()->getType().getNominalSize()) 343 { 344 case 1: writeTriplet(visit, "int(", NULL, ")"); break; 345 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break; 346 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break; 347 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break; 348 default: UNREACHABLE(); 349 } 350 break; 351 352 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break; 353 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break; 354 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break; 355 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break; 356 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break; 357 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break; 358 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break; 359 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break; 360 361 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break; 362 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break; 363 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break; 364 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break; 365 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break; 366 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break; 367 368 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break; 369 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break; 370 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break; 371 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break; 372 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break; 373 374 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break; 375 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break; 376 377 case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break; 378 case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break; 379 case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break; 380 381 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break; 382 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break; 383 384 default: UNREACHABLE(); break; 385 } 386 387 return true; 388 } 389 390 bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node) 391 { 392 TInfoSinkBase& out = objSink(); 393 394 if (node->usesTernaryOperator()) 395 { 396 // Notice two brackets at the beginning and end. The outer ones 397 // encapsulate the whole ternary expression. This preserves the 398 // order of precedence when ternary expressions are used in a 399 // compound expression, i.e., c = 2 * (a < b ? 1 : 2). 400 out << "(("; 401 node->getCondition()->traverse(this); 402 out << ") ? ("; 403 node->getTrueBlock()->traverse(this); 404 out << ") : ("; 405 node->getFalseBlock()->traverse(this); 406 out << "))"; 407 } 408 else 409 { 410 out << "if ("; 411 node->getCondition()->traverse(this); 412 out << ")\n"; 413 414 incrementDepth(); 415 visitCodeBlock(node->getTrueBlock()); 416 417 if (node->getFalseBlock()) 418 { 419 out << "else\n"; 420 visitCodeBlock(node->getFalseBlock()); 421 } 422 decrementDepth(); 423 } 424 return false; 425 } 426 427 bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node) 428 { 429 bool visitChildren = true; 430 TInfoSinkBase& out = objSink(); 431 switch (node->getOp()) 432 { 433 case EOpSequence: { 434 // Scope the sequences except when at the global scope. 435 if (depth > 0) out << "{\n"; 436 437 incrementDepth(); 438 const TIntermSequence& sequence = node->getSequence(); 439 for (TIntermSequence::const_iterator iter = sequence.begin(); 440 iter != sequence.end(); ++iter) 441 { 442 TIntermNode* node = *iter; 443 ASSERT(node != NULL); 444 node->traverse(this); 445 446 if (isSingleStatement(node)) 447 out << ";\n"; 448 } 449 decrementDepth(); 450 451 // Scope the sequences except when at the global scope. 452 if (depth > 0) out << "}\n"; 453 visitChildren = false; 454 break; 455 } 456 case EOpPrototype: { 457 // Function declaration. 458 ASSERT(visit == PreVisit); 459 TString returnType = getTypeName(node->getType()); 460 out << returnType << " " << node->getName(); 461 462 out << "("; 463 writeFunctionParameters(node->getSequence()); 464 out << ")"; 465 466 visitChildren = false; 467 break; 468 } 469 case EOpFunction: { 470 // Function definition. 471 ASSERT(visit == PreVisit); 472 TString returnType = getTypeName(node->getType()); 473 TString functionName = TFunction::unmangleName(node->getName()); 474 out << returnType << " " << functionName; 475 476 incrementDepth(); 477 // Function definition node contains one or two children nodes 478 // representing function parameters and function body. The latter 479 // is not present in case of empty function bodies. 480 const TIntermSequence& sequence = node->getSequence(); 481 ASSERT((sequence.size() == 1) || (sequence.size() == 2)); 482 TIntermSequence::const_iterator seqIter = sequence.begin(); 483 484 // Traverse function parameters. 485 TIntermAggregate* params = (*seqIter)->getAsAggregate(); 486 ASSERT(params != NULL); 487 ASSERT(params->getOp() == EOpParameters); 488 params->traverse(this); 489 490 // Traverse function body. 491 TIntermAggregate* body = ++seqIter != sequence.end() ? 492 (*seqIter)->getAsAggregate() : NULL; 493 visitCodeBlock(body); 494 decrementDepth(); 495 496 // Fully processed; no need to visit children. 497 visitChildren = false; 498 break; 499 } 500 case EOpFunctionCall: 501 // Function call. 502 if (visit == PreVisit) 503 { 504 TString functionName = TFunction::unmangleName(node->getName()); 505 out << functionName << "("; 506 } 507 else if (visit == InVisit) 508 { 509 out << ", "; 510 } 511 else 512 { 513 out << ")"; 514 } 515 break; 516 case EOpParameters: { 517 // Function parameters. 518 ASSERT(visit == PreVisit); 519 out << "("; 520 writeFunctionParameters(node->getSequence()); 521 out << ")"; 522 visitChildren = false; 523 break; 524 } 525 case EOpDeclaration: { 526 // Variable declaration. 527 if (visit == PreVisit) 528 { 529 const TIntermSequence& sequence = node->getSequence(); 530 const TIntermTyped* variable = sequence.front()->getAsTyped(); 531 writeVariableType(variable->getType()); 532 out << " "; 533 mDeclaringVariables = true; 534 } 535 else if (visit == InVisit) 536 { 537 out << ", "; 538 mDeclaringVariables = true; 539 } 540 else 541 { 542 mDeclaringVariables = false; 543 } 544 break; 545 } 546 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; 547 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break; 548 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break; 549 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break; 550 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break; 551 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break; 552 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break; 553 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break; 554 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break; 555 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break; 556 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break; 557 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break; 558 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break; 559 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break; 560 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break; 561 case EOpConstructStruct: 562 if (visit == PreVisit) 563 { 564 const TType& type = node->getType(); 565 ASSERT(type.getBasicType() == EbtStruct); 566 out << type.getTypeName() << "("; 567 } 568 else if (visit == InVisit) 569 { 570 out << ", "; 571 } 572 else 573 { 574 out << ")"; 575 } 576 break; 577 578 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break; 579 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break; 580 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break; 581 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break; 582 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break; 583 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break; 584 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break; 585 586 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break; 587 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break; 588 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break; 589 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break; 590 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break; 591 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break; 592 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break; 593 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break; 594 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break; 595 596 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break; 597 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break; 598 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break; 599 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break; 600 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break; 601 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break; 602 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break; 603 604 default: UNREACHABLE(); break; 605 } 606 return visitChildren; 607 } 608 609 bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node) 610 { 611 TInfoSinkBase& out = objSink(); 612 613 incrementDepth(); 614 // Loop header. 615 TLoopType loopType = node->getType(); 616 if (loopType == ELoopFor) // for loop 617 { 618 out << "for ("; 619 if (node->getInit()) 620 node->getInit()->traverse(this); 621 out << "; "; 622 623 if (node->getCondition()) 624 node->getCondition()->traverse(this); 625 out << "; "; 626 627 if (node->getExpression()) 628 node->getExpression()->traverse(this); 629 out << ")\n"; 630 } 631 else if (loopType == ELoopWhile) // while loop 632 { 633 out << "while ("; 634 ASSERT(node->getCondition() != NULL); 635 node->getCondition()->traverse(this); 636 out << ")\n"; 637 } 638 else // do-while loop 639 { 640 ASSERT(loopType == ELoopDoWhile); 641 out << "do\n"; 642 } 643 644 // Loop body. 645 visitCodeBlock(node->getBody()); 646 647 // Loop footer. 648 if (loopType == ELoopDoWhile) // do-while loop 649 { 650 out << "while ("; 651 ASSERT(node->getCondition() != NULL); 652 node->getCondition()->traverse(this); 653 out << ");\n"; 654 } 655 decrementDepth(); 656 657 // No need to visit children. They have been already processed in 658 // this function. 659 return false; 660 } 661 662 bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node) 663 { 664 switch (node->getFlowOp()) 665 { 666 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break; 667 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break; 668 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break; 669 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break; 670 default: UNREACHABLE(); break; 671 } 672 673 return true; 674 } 675 676 void TOutputGLSL::visitCodeBlock(TIntermNode* node) { 677 TInfoSinkBase &out = objSink(); 678 if (node != NULL) 679 { 680 node->traverse(this); 681 // Single statements not part of a sequence need to be terminated 682 // with semi-colon. 683 if (isSingleStatement(node)) 684 out << ";\n"; 685 } 686 else 687 { 688 out << "{\n}\n"; // Empty code block. 689 } 690 } 691