Home | History | Annotate | Download | only in translator
      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