• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //
6 
7 #include "compiler/OutputGLSLBase.h"
8 #include "compiler/debug.h"
9 
10 #include <cfloat>
11 
12 namespace
13 {
arrayBrackets(const TType & type)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 
isSingleStatement(TIntermNode * node)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
41 
TOutputGLSLBase(TInfoSinkBase & objSink,ShArrayIndexClampingStrategy clampingStrategy,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable & symbolTable)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 }
56 
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)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 }
73 
writeVariableType(const TType & type)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 }
93 
writeFunctionParameters(const TIntermSequence & args)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);
102 
103         const TType& type = arg->getType();
104         writeVariableType(type);
105 
106         const TString& name = arg->getSymbol();
107         if (!name.empty())
108             out << " " << hashName(name);
109         if (type.isArray())
110             out << arrayBrackets(type);
111 
112         // Put a comma if this is not the last argument.
113         if (iter != args.end() - 1)
114             out << ", ";
115     }
116 }
117 
writeConstantUnion(const TType & type,const ConstantUnion * pConstUnion)118 const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
119                                                          const ConstantUnion* pConstUnion)
120 {
121     TInfoSinkBase& out = objSink();
122 
123     if (type.getBasicType() == EbtStruct)
124     {
125         const TStructure* structure = type.getStruct();
126         out << hashName(structure->name()) << "(";
127 
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 }
158 
visitSymbol(TIntermSymbol * node)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());
166 
167     if (mDeclaringVariables && node->getType().isArray())
168         out << arrayBrackets(node->getType());
169 }
170 
visitConstantUnion(TIntermConstantUnion * node)171 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
172 {
173     writeConstantUnion(node->getType(), node->getUnionArrayPointer());
174 }
175 
visitBinary(Visit visit,TIntermBinary * node)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;
202 
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();
222 
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                     }
232 
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)];
257 
258                 TString fieldName = field->name();
259                 if (!mSymbolTable.findBuiltIn(structure->name()))
260                     fieldName = hashName(fieldName);
261 
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;
291 
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;
303 
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;
312 
313         case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
314         case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
315         case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
316         default: UNREACHABLE(); break;
317     }
318 
319     return visitChildren;
320 }
321 
visitUnary(Visit visit,TIntermUnary * node)322 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
323 {
324     TString preString;
325     TString postString = ")";
326 
327     switch (node->getOp())
328     {
329         case EOpNegative: preString = "(-"; break;
330         case EOpVectorLogicalNot: preString = "not("; break;
331         case EOpLogicalNot: preString = "(!"; break;
332 
333         case EOpPostIncrement: preString = "("; postString = "++)"; break;
334         case EOpPostDecrement: preString = "("; postString = "--)"; break;
335         case EOpPreIncrement: preString = "(++"; break;
336         case EOpPreDecrement: preString = "(--"; break;
337 
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;
371 
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;
380 
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;
387 
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;
393 
394         case EOpLength: preString = "length("; break;
395         case EOpNormalize: preString = "normalize("; break;
396 
397         case EOpDFdx: preString = "dFdx("; break;
398         case EOpDFdy: preString = "dFdy("; break;
399         case EOpFwidth: preString = "fwidth("; break;
400 
401         case EOpAny: preString = "any("; break;
402         case EOpAll: preString = "all("; break;
403 
404         default: UNREACHABLE(); break;
405     }
406 
407     if (visit == PreVisit && node->getUseEmulatedFunction())
408         preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
409     writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
410 
411     return true;
412 }
413 
visitSelection(Visit visit,TIntermSelection * node)414 bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
415 {
416     TInfoSinkBase& out = objSink();
417 
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";
437 
438         incrementDepth(node);
439         visitCodeBlock(node->getTrueBlock());
440 
441         if (node->getFalseBlock())
442         {
443             out << "else\n";
444             visitCodeBlock(node->getFalseBlock());
445         }
446         decrementDepth();
447     }
448     return false;
449 }
450 
visitAggregate(Visit visit,TIntermAggregate * node)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";
462 
463             incrementDepth(node);
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);
471 
472                 if (isSingleStatement(node))
473                     out << ";\n";
474             }
475             decrementDepth();
476 
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());
487 
488             out << "(";
489             writeFunctionParameters(node->getSequence());
490             out << ")";
491 
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());
500 
501             incrementDepth(node);
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();
508 
509             // Traverse function parameters.
510             TIntermAggregate* params = (*seqIter)->getAsAggregate();
511             ASSERT(params != NULL);
512             ASSERT(params->getOp() == EOpParameters);
513             params->traverse(this);
514 
515             // Traverse function body.
516             TIntermAggregate* body = ++seqIter != sequence.end() ?
517                 (*seqIter)->getAsAggregate() : NULL;
518             visitCodeBlock(body);
519             decrementDepth();
520 
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;
601 
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;
609 
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;
619 
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;
627 
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 }
636 
visitLoop(Visit visit,TIntermLoop * node)637 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
638 {
639     TInfoSinkBase& out = objSink();
640 
641     incrementDepth(node);
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 << "; ";
651 
652             if (node->getCondition())
653                 node->getCondition()->traverse(this);
654             out << "; ";
655 
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     }
673 
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     }
691 
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();
701 
702     // No need to visit children. They have been already processed in
703     // this function.
704     return false;
705 }
706 
visitBranch(Visit visit,TIntermBranch * node)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     }
717 
718     return true;
719 }
720 
visitCodeBlock(TIntermNode * node)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 }
736 
getTypeName(const TType & type)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 }
765 
hashName(const TString & name)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 }
777 
hashVariableName(const TString & name)778 TString TOutputGLSLBase::hashVariableName(const TString& name)
779 {
780     if (mSymbolTable.findBuiltIn(name) != NULL)
781         return name;
782     return hashName(name);
783 }
784 
hashFunctionName(const TString & mangled_name)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 }
792 
structDeclared(const TStructure * structure) const793 bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
794 {
795     return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
796 }
797 
declareStruct(const TStructure * structure)798 void TOutputGLSLBase::declareStruct(const TStructure* structure)
799 {
800     TInfoSinkBase& out = objSink();
801 
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 << "}";
815 
816     mDeclaredStructs.insert(structure->name());
817 }
818