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