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