gfx/angle/src/compiler/OutputGLSLBase.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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 //
     7 #include "compiler/OutputGLSLBase.h"
     8 #include "compiler/compiler_debug.h"
    10 #include <cfloat>
    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 }
    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
    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 }
    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 }
    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 }
    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);
   103         const TType& type = arg->getType();
   104         writeVariableType(type);
   106         const TString& name = arg->getSymbol();
   107         if (!name.empty())
   108             out << " " << hashName(name);
   109         if (type.isArray())
   110             out << arrayBrackets(type);
   112         // Put a comma if this is not the last argument.
   113         if (iter != args.end() - 1)
   114             out << ", ";
   115     }
   116 }
   118 const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
   119                                                          const ConstantUnion* pConstUnion)
   120 {
   121     TInfoSinkBase& out = objSink();
   123     if (type.getBasicType() == EbtStruct)
   124     {
   125         const TStructure* structure = type.getStruct();
   126         out << hashName(structure->name()) << "(";
   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 }
   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());
   167     if (mDeclaringVariables && node->getType().isArray())
   168         out << arrayBrackets(node->getType());
   169 }
   171 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
   172 {
   173     writeConstantUnion(node->getType(), node->getUnionArrayPointer());
   174 }
   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;
   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();
   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                     }
   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)];
   258                 TString fieldName = field->name();
   259                 if (!mSymbolTable.findBuiltIn(structure->name()))
   260                     fieldName = hashName(fieldName);
   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;
   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;
   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;
   313         case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
   314         case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
   315         case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
   316         default: UNREACHABLE(); break;
   317     }
   319     return visitChildren;
   320 }
   322 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
   323 {
   324     TString preString;
   325     TString postString = ")";
   327     switch (node->getOp())
   328     {
   329         case EOpNegative: preString = "(-"; break;
   330         case EOpVectorLogicalNot: preString = "not("; break;
   331         case EOpLogicalNot: preString = "(!"; break;
   333         case EOpPostIncrement: preString = "("; postString = "++)"; break;
   334         case EOpPostDecrement: preString = "("; postString = "--)"; break;
   335         case EOpPreIncrement: preString = "(++"; break;
   336         case EOpPreDecrement: preString = "(--"; break;
   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;
   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;
   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;
   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;
   394         case EOpLength: preString = "length("; break;
   395         case EOpNormalize: preString = "normalize("; break;
   397         case EOpDFdx: preString = "dFdx("; break;
   398         case EOpDFdy: preString = "dFdy("; break;
   399         case EOpFwidth: preString = "fwidth("; break;
   401         case EOpAny: preString = "any("; break;
   402         case EOpAll: preString = "all("; break;
   404         default: UNREACHABLE(); break;
   405     }
   407     if (visit == PreVisit && node->getUseEmulatedFunction())
   408         preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
   409     writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
   411     return true;
   412 }
   414 bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
   415 {
   416     TInfoSinkBase& out = objSink();
   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";
   438         incrementDepth();
   439         visitCodeBlock(node->getTrueBlock());
   441         if (node->getFalseBlock())
   442         {
   443             out << "else\n";
   444             visitCodeBlock(node->getFalseBlock());
   445         }
   446         decrementDepth();
   447     }
   448     return false;
   449 }
   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";
   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);
   472                 if (isSingleStatement(node))
   473                     out << ";\n";
   474             }
   475             decrementDepth();
   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());
   488             out << "(";
   489             writeFunctionParameters(node->getSequence());
   490             out << ")";
   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());
   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();
   509             // Traverse function parameters.
   510             TIntermAggregate* params = (*seqIter)->getAsAggregate();
   511             ASSERT(params != NULL);
   512             ASSERT(params->getOp() == EOpParameters);
   513             params->traverse(this);
   515             // Traverse function body.
   516             TIntermAggregate* body = ++seqIter != sequence.end() ?
   517                 (*seqIter)->getAsAggregate() : NULL;
   518             visitCodeBlock(body);
   519             decrementDepth();
   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;
   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;
   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;
   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;
   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 }
   637 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
   638 {
   639     TInfoSinkBase& out = objSink();
   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 << "; ";
   652             if (node->getCondition())
   653                 node->getCondition()->traverse(this);
   654             out << "; ";
   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     }
   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     }
   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();
   702     // No need to visit children. They have been already processed in
   703     // this function.
   704     return false;
   705 }
   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     }
   718     return true;
   719 }
   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 }
   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 }
   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 }
   778 TString TOutputGLSLBase::hashVariableName(const TString& name)
   779 {
   780     if (mSymbolTable.findBuiltIn(name) != NULL)
   781         return name;
   782     return hashName(name);
   783 }
   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 }
   793 bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
   794 {
   795     return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
   796 }
   798 void TOutputGLSLBase::declareStruct(const TStructure* structure)
   799 {
   800     TInfoSinkBase& out = objSink();
   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 << "}";
   816     mDeclaredStructs.insert(structure->name());
   817 }

mercurial