6d07cccc04fc252fb1029ccd14ce52f1cc79192d
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / OutputGLSLBase.cpp
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