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