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 
9 #include "common/debug.h"
10 
11 #include <cfloat>
12 
13 namespace sh
14 {
15 
16 namespace
17 {
arrayBrackets(const TType & type)18 TString arrayBrackets(const TType &type)
19 {
20     ASSERT(type.isArray());
21     TInfoSinkBase out;
22     out << "[" << type.getArraySize() << "]";
23     return TString(out.c_str());
24 }
25 
isSingleStatement(TIntermNode * node)26 bool isSingleStatement(TIntermNode *node)
27 {
28     if (node->getAsFunctionDefinition())
29     {
30         return false;
31     }
32     else if (node->getAsBlock())
33     {
34         return false;
35     }
36     else if (node->getAsIfElseNode())
37     {
38         return false;
39     }
40     else if (node->getAsLoopNode())
41     {
42         return false;
43     }
44     else if (node->getAsSwitchNode())
45     {
46         return false;
47     }
48     else if (node->getAsCaseNode())
49     {
50         return false;
51     }
52     return true;
53 }
54 
55 // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
56 // variables with specified layout qualifiers are copied. Additional checks are needed against the
57 // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
58 // TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
59 // NeedsToWriteLayoutQualifier.
NeedsToWriteLayoutQualifier(const TType & type)60 bool NeedsToWriteLayoutQualifier(const TType &type)
61 {
62     if (type.getBasicType() == EbtInterfaceBlock)
63     {
64         return false;
65     }
66 
67     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
68 
69     if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
70         layoutQualifier.location >= 0)
71     {
72         return true;
73     }
74     if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
75     {
76         return true;
77     }
78     return false;
79 }
80 
81 }  // namespace
82 
TOutputGLSLBase(TInfoSinkBase & objSink,ShArrayIndexClampingStrategy clampingStrategy,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable & symbolTable,sh::GLenum shaderType,int shaderVersion,ShShaderOutput output,ShCompileOptions compileOptions)83 TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
84                                  ShArrayIndexClampingStrategy clampingStrategy,
85                                  ShHashFunction64 hashFunction,
86                                  NameMap &nameMap,
87                                  TSymbolTable &symbolTable,
88                                  sh::GLenum shaderType,
89                                  int shaderVersion,
90                                  ShShaderOutput output,
91                                  ShCompileOptions compileOptions)
92     : TIntermTraverser(true, true, true),
93       mObjSink(objSink),
94       mDeclaringVariables(false),
95       mClampingStrategy(clampingStrategy),
96       mHashFunction(hashFunction),
97       mNameMap(nameMap),
98       mSymbolTable(symbolTable),
99       mShaderType(shaderType),
100       mShaderVersion(shaderVersion),
101       mOutput(output),
102       mCompileOptions(compileOptions)
103 {
104 }
105 
writeInvariantQualifier(const TType & type)106 void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
107 {
108     if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
109     {
110         TInfoSinkBase &out = objSink();
111         out << "invariant ";
112     }
113 }
114 
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)115 void TOutputGLSLBase::writeTriplet(
116     Visit visit, const char *preStr, const char *inStr, const char *postStr)
117 {
118     TInfoSinkBase &out = objSink();
119     if (visit == PreVisit && preStr)
120         out << preStr;
121     else if (visit == InVisit && inStr)
122         out << inStr;
123     else if (visit == PostVisit && postStr)
124         out << postStr;
125 }
126 
writeBuiltInFunctionTriplet(Visit visit,const char * preStr,bool useEmulatedFunction)127 void TOutputGLSLBase::writeBuiltInFunctionTriplet(
128     Visit visit, const char *preStr, bool useEmulatedFunction)
129 {
130     TString preString = useEmulatedFunction ?
131         BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
132     writeTriplet(visit, preString.c_str(), ", ", ")");
133 }
134 
writeLayoutQualifier(const TType & type)135 void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
136 {
137     if (!NeedsToWriteLayoutQualifier(type))
138     {
139         return;
140     }
141 
142     TInfoSinkBase &out                      = objSink();
143     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
144     out << "layout(";
145 
146     if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
147     {
148         if (layoutQualifier.location >= 0)
149         {
150             out << "location = " << layoutQualifier.location;
151         }
152     }
153 
154     if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
155     {
156         ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
157         out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
158     }
159 
160     out << ") ";
161 }
162 
mapQualifierToString(TQualifier qualifier)163 const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
164 {
165     if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
166         (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
167     {
168         switch (qualifier)
169         {
170             // The return string is consistent with sh::getQualifierString() from
171             // BaseTypes.h minus the "centroid" keyword.
172             case EvqCentroid:
173                 return "";
174             case EvqCentroidIn:
175                 return "smooth in";
176             case EvqCentroidOut:
177                 return "smooth out";
178             default:
179                 break;
180         }
181     }
182     if (sh::IsGLSL130OrNewer(mOutput))
183     {
184         switch (qualifier)
185         {
186             case EvqAttribute:
187                 return "in";
188             case EvqVaryingIn:
189                 return "in";
190             case EvqVaryingOut:
191                 return "out";
192             default:
193                 break;
194         }
195     }
196     return sh::getQualifierString(qualifier);
197 }
198 
writeVariableType(const TType & type)199 void TOutputGLSLBase::writeVariableType(const TType &type)
200 {
201     TQualifier qualifier = type.getQualifier();
202     TInfoSinkBase &out = objSink();
203     if (type.isInvariant())
204     {
205         writeInvariantQualifier(type);
206     }
207     if (type.getBasicType() == EbtInterfaceBlock)
208     {
209         TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
210         declareInterfaceBlockLayout(interfaceBlock);
211     }
212     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
213     {
214         const char *qualifierString = mapQualifierToString(qualifier);
215         if (qualifierString && qualifierString[0] != '\0')
216         {
217             out << qualifierString << " ";
218         }
219     }
220 
221     const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
222     if (memoryQualifier.readonly)
223     {
224         ASSERT(IsImage(type.getBasicType()));
225         out << "readonly ";
226     }
227 
228     if (memoryQualifier.writeonly)
229     {
230         ASSERT(IsImage(type.getBasicType()));
231         out << "writeonly ";
232     }
233 
234     if (memoryQualifier.coherent)
235     {
236         ASSERT(IsImage(type.getBasicType()));
237         out << "coherent ";
238     }
239 
240     if (memoryQualifier.restrictQualifier)
241     {
242         ASSERT(IsImage(type.getBasicType()));
243         out << "restrict ";
244     }
245 
246     if (memoryQualifier.volatileQualifier)
247     {
248         ASSERT(IsImage(type.getBasicType()));
249         out << "volatile ";
250     }
251 
252     // Declare the struct if we have not done so already.
253     if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
254     {
255         TStructure *structure = type.getStruct();
256 
257         declareStruct(structure);
258 
259         if (!structure->name().empty())
260         {
261             mDeclaredStructs.insert(structure->uniqueId());
262         }
263     }
264     else if (type.getBasicType() == EbtInterfaceBlock)
265     {
266         TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
267         declareInterfaceBlock(interfaceBlock);
268     }
269     else
270     {
271         if (writeVariablePrecision(type.getPrecision()))
272             out << " ";
273         out << getTypeName(type);
274     }
275 }
276 
writeFunctionParameters(const TIntermSequence & args)277 void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
278 {
279     TInfoSinkBase &out = objSink();
280     for (TIntermSequence::const_iterator iter = args.begin();
281          iter != args.end(); ++iter)
282     {
283         const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
284         ASSERT(arg != NULL);
285 
286         const TType &type = arg->getType();
287         writeVariableType(type);
288 
289         if (!arg->getName().getString().empty())
290             out << " " << hashName(arg->getName());
291         if (type.isArray())
292             out << arrayBrackets(type);
293 
294         // Put a comma if this is not the last argument.
295         if (iter != args.end() - 1)
296             out << ", ";
297     }
298 }
299 
writeConstantUnion(const TType & type,const TConstantUnion * pConstUnion)300 const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
301     const TType &type, const TConstantUnion *pConstUnion)
302 {
303     TInfoSinkBase &out = objSink();
304 
305     if (type.getBasicType() == EbtStruct)
306     {
307         const TStructure *structure = type.getStruct();
308         out << hashName(TName(structure->name())) << "(";
309 
310         const TFieldList &fields = structure->fields();
311         for (size_t i = 0; i < fields.size(); ++i)
312         {
313             const TType *fieldType = fields[i]->type();
314             ASSERT(fieldType != NULL);
315             pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
316             if (i != fields.size() - 1)
317                 out << ", ";
318         }
319         out << ")";
320     }
321     else
322     {
323         size_t size = type.getObjectSize();
324         bool writeType = size > 1;
325         if (writeType)
326             out << getTypeName(type) << "(";
327         for (size_t i = 0; i < size; ++i, ++pConstUnion)
328         {
329             switch (pConstUnion->getType())
330             {
331               case EbtFloat:
332                 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
333                 break;
334               case EbtInt:
335                 out << pConstUnion->getIConst();
336                 break;
337               case EbtUInt:
338                 out << pConstUnion->getUConst() << "u";
339                 break;
340               case EbtBool:
341                 out << pConstUnion->getBConst();
342                 break;
343               default: UNREACHABLE();
344             }
345             if (i != size - 1)
346                 out << ", ";
347         }
348         if (writeType)
349             out << ")";
350     }
351     return pConstUnion;
352 }
353 
writeConstructorTriplet(Visit visit,const TType & type)354 void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
355 {
356     TInfoSinkBase &out = objSink();
357     if (visit == PreVisit)
358     {
359         if (type.isArray())
360         {
361             out << getTypeName(type);
362             out << arrayBrackets(type);
363             out << "(";
364         }
365         else
366         {
367             out << getTypeName(type) << "(";
368         }
369     }
370     else
371     {
372         writeTriplet(visit, nullptr, ", ", ")");
373     }
374 }
375 
visitSymbol(TIntermSymbol * node)376 void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
377 {
378     TInfoSinkBase &out = objSink();
379     if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
380         out << mLoopUnrollStack.getLoopIndexValue(node);
381     else
382         out << hashVariableName(node->getName());
383 
384     if (mDeclaringVariables && node->getType().isArray())
385         out << arrayBrackets(node->getType());
386 }
387 
visitConstantUnion(TIntermConstantUnion * node)388 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
389 {
390     writeConstantUnion(node->getType(), node->getUnionArrayPointer());
391 }
392 
visitSwizzle(Visit visit,TIntermSwizzle * node)393 bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
394 {
395     TInfoSinkBase &out = objSink();
396     if (visit == PostVisit)
397     {
398         out << ".";
399         node->writeOffsetsAsXYZW(&out);
400     }
401     return true;
402 }
403 
visitBinary(Visit visit,TIntermBinary * node)404 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
405 {
406     bool visitChildren = true;
407     TInfoSinkBase &out = objSink();
408     switch (node->getOp())
409     {
410         case EOpComma:
411             writeTriplet(visit, "(", ", ", ")");
412             break;
413         case EOpInitialize:
414             if (visit == InVisit)
415             {
416                 out << " = ";
417                 // RHS of initialize is not being declared.
418                 mDeclaringVariables = false;
419             }
420             break;
421         case EOpAssign:
422             writeTriplet(visit, "(", " = ", ")");
423             break;
424         case EOpAddAssign:
425             writeTriplet(visit, "(", " += ", ")");
426             break;
427         case EOpSubAssign:
428             writeTriplet(visit, "(", " -= ", ")");
429             break;
430         case EOpDivAssign:
431             writeTriplet(visit, "(", " /= ", ")");
432             break;
433         case EOpIModAssign:
434             writeTriplet(visit, "(", " %= ", ")");
435             break;
436         // Notice the fall-through.
437         case EOpMulAssign:
438         case EOpVectorTimesMatrixAssign:
439         case EOpVectorTimesScalarAssign:
440         case EOpMatrixTimesScalarAssign:
441         case EOpMatrixTimesMatrixAssign:
442             writeTriplet(visit, "(", " *= ", ")");
443             break;
444         case EOpBitShiftLeftAssign:
445             writeTriplet(visit, "(", " <<= ", ")");
446             break;
447         case EOpBitShiftRightAssign:
448             writeTriplet(visit, "(", " >>= ", ")");
449             break;
450         case EOpBitwiseAndAssign:
451             writeTriplet(visit, "(", " &= ", ")");
452             break;
453         case EOpBitwiseXorAssign:
454             writeTriplet(visit, "(", " ^= ", ")");
455             break;
456         case EOpBitwiseOrAssign:
457             writeTriplet(visit, "(", " |= ", ")");
458             break;
459 
460         case EOpIndexDirect:
461             writeTriplet(visit, NULL, "[", "]");
462             break;
463         case EOpIndexIndirect:
464             if (node->getAddIndexClamp())
465             {
466                 if (visit == InVisit)
467                 {
468                     if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
469                         out << "[int(clamp(float(";
470                     else
471                         out << "[webgl_int_clamp(";
472                 }
473                 else if (visit == PostVisit)
474                 {
475                     int maxSize;
476                     TIntermTyped *left = node->getLeft();
477                     TType leftType     = left->getType();
478 
479                     if (left->isArray())
480                     {
481                         // The shader will fail validation if the array length is not > 0.
482                         maxSize = static_cast<int>(leftType.getArraySize()) - 1;
483                     }
484                     else
485                     {
486                         maxSize = leftType.getNominalSize() - 1;
487                     }
488 
489                     if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
490                         out << "), 0.0, float(" << maxSize << ")))]";
491                     else
492                         out << ", 0, " << maxSize << ")]";
493                 }
494             }
495             else
496             {
497                 writeTriplet(visit, NULL, "[", "]");
498             }
499             break;
500         case EOpIndexDirectStruct:
501             if (visit == InVisit)
502             {
503                 // Here we are writing out "foo.bar", where "foo" is struct
504                 // and "bar" is field. In AST, it is represented as a binary
505                 // node, where left child represents "foo" and right child "bar".
506                 // The node itself represents ".". The struct field "bar" is
507                 // actually stored as an index into TStructure::fields.
508                 out << ".";
509                 const TStructure *structure       = node->getLeft()->getType().getStruct();
510                 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
511                 const TField *field               = structure->fields()[index->getIConst(0)];
512 
513                 TString fieldName = field->name();
514                 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
515                     fieldName = hashName(TName(fieldName));
516 
517                 out << fieldName;
518                 visitChildren = false;
519             }
520             break;
521         case EOpIndexDirectInterfaceBlock:
522             if (visit == InVisit)
523             {
524                 out << ".";
525                 const TInterfaceBlock *interfaceBlock =
526                     node->getLeft()->getType().getInterfaceBlock();
527                 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
528                 const TField *field               = interfaceBlock->fields()[index->getIConst(0)];
529 
530                 TString fieldName = field->name();
531                 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
532                 fieldName = hashName(TName(fieldName));
533 
534                 out << fieldName;
535                 visitChildren = false;
536             }
537             break;
538 
539         case EOpAdd:
540             writeTriplet(visit, "(", " + ", ")");
541             break;
542         case EOpSub:
543             writeTriplet(visit, "(", " - ", ")");
544             break;
545         case EOpMul:
546             writeTriplet(visit, "(", " * ", ")");
547             break;
548         case EOpDiv:
549             writeTriplet(visit, "(", " / ", ")");
550             break;
551         case EOpIMod:
552             writeTriplet(visit, "(", " % ", ")");
553             break;
554         case EOpBitShiftLeft:
555             writeTriplet(visit, "(", " << ", ")");
556             break;
557         case EOpBitShiftRight:
558             writeTriplet(visit, "(", " >> ", ")");
559             break;
560         case EOpBitwiseAnd:
561             writeTriplet(visit, "(", " & ", ")");
562             break;
563         case EOpBitwiseXor:
564             writeTriplet(visit, "(", " ^ ", ")");
565             break;
566         case EOpBitwiseOr:
567             writeTriplet(visit, "(", " | ", ")");
568             break;
569 
570         case EOpEqual:
571             writeTriplet(visit, "(", " == ", ")");
572             break;
573         case EOpNotEqual:
574             writeTriplet(visit, "(", " != ", ")");
575             break;
576         case EOpLessThan:
577             writeTriplet(visit, "(", " < ", ")");
578             break;
579         case EOpGreaterThan:
580             writeTriplet(visit, "(", " > ", ")");
581             break;
582         case EOpLessThanEqual:
583             writeTriplet(visit, "(", " <= ", ")");
584             break;
585         case EOpGreaterThanEqual:
586             writeTriplet(visit, "(", " >= ", ")");
587             break;
588 
589         // Notice the fall-through.
590         case EOpVectorTimesScalar:
591         case EOpVectorTimesMatrix:
592         case EOpMatrixTimesVector:
593         case EOpMatrixTimesScalar:
594         case EOpMatrixTimesMatrix:
595             writeTriplet(visit, "(", " * ", ")");
596             break;
597 
598         case EOpLogicalOr:
599             writeTriplet(visit, "(", " || ", ")");
600             break;
601         case EOpLogicalXor:
602             writeTriplet(visit, "(", " ^^ ", ")");
603             break;
604         case EOpLogicalAnd:
605             writeTriplet(visit, "(", " && ", ")");
606             break;
607         default:
608             UNREACHABLE();
609     }
610 
611     return visitChildren;
612 }
613 
visitUnary(Visit visit,TIntermUnary * node)614 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
615 {
616     TString preString;
617     TString postString = ")";
618 
619     switch (node->getOp())
620     {
621       case EOpNegative: preString = "(-"; break;
622       case EOpPositive: preString = "(+"; break;
623       case EOpVectorLogicalNot: preString = "not("; break;
624       case EOpLogicalNot: preString = "(!"; break;
625       case EOpBitwiseNot: preString = "(~"; break;
626 
627       case EOpPostIncrement: preString = "("; postString = "++)"; break;
628       case EOpPostDecrement: preString = "("; postString = "--)"; break;
629       case EOpPreIncrement: preString = "(++"; break;
630       case EOpPreDecrement: preString = "(--"; break;
631 
632       case EOpRadians:
633         preString = "radians(";
634         break;
635       case EOpDegrees:
636         preString = "degrees(";
637         break;
638       case EOpSin:
639         preString = "sin(";
640         break;
641       case EOpCos:
642         preString = "cos(";
643         break;
644       case EOpTan:
645         preString = "tan(";
646         break;
647       case EOpAsin:
648         preString = "asin(";
649         break;
650       case EOpAcos:
651         preString = "acos(";
652         break;
653       case EOpAtan:
654         preString = "atan(";
655         break;
656 
657       case EOpSinh:
658         preString = "sinh(";
659         break;
660       case EOpCosh:
661         preString = "cosh(";
662         break;
663       case EOpTanh:
664         preString = "tanh(";
665         break;
666       case EOpAsinh:
667         preString = "asinh(";
668         break;
669       case EOpAcosh:
670         preString = "acosh(";
671         break;
672       case EOpAtanh:
673         preString = "atanh(";
674         break;
675 
676       case EOpExp:
677         preString = "exp(";
678         break;
679       case EOpLog:
680         preString = "log(";
681         break;
682       case EOpExp2:
683         preString = "exp2(";
684         break;
685       case EOpLog2:
686         preString = "log2(";
687         break;
688       case EOpSqrt:
689         preString = "sqrt(";
690         break;
691       case EOpInverseSqrt:
692         preString = "inversesqrt(";
693         break;
694 
695       case EOpAbs:
696         preString = "abs(";
697         break;
698       case EOpSign:
699         preString = "sign(";
700         break;
701       case EOpFloor:
702         preString = "floor(";
703         break;
704       case EOpTrunc:
705         preString = "trunc(";
706         break;
707       case EOpRound:
708         preString = "round(";
709         break;
710       case EOpRoundEven:
711         preString = "roundEven(";
712         break;
713       case EOpCeil:
714         preString = "ceil(";
715         break;
716       case EOpFract:
717         preString = "fract(";
718         break;
719       case EOpIsNan:
720         preString = "isnan(";
721         break;
722       case EOpIsInf:
723         preString = "isinf(";
724         break;
725 
726       case EOpFloatBitsToInt:
727         preString = "floatBitsToInt(";
728         break;
729       case EOpFloatBitsToUint:
730         preString = "floatBitsToUint(";
731         break;
732       case EOpIntBitsToFloat:
733         preString = "intBitsToFloat(";
734         break;
735       case EOpUintBitsToFloat:
736         preString = "uintBitsToFloat(";
737         break;
738 
739       case EOpPackSnorm2x16:
740         preString = "packSnorm2x16(";
741         break;
742       case EOpPackUnorm2x16:
743         preString = "packUnorm2x16(";
744         break;
745       case EOpPackHalf2x16:
746         preString = "packHalf2x16(";
747         break;
748       case EOpUnpackSnorm2x16:
749         preString = "unpackSnorm2x16(";
750         break;
751       case EOpUnpackUnorm2x16:
752         preString = "unpackUnorm2x16(";
753         break;
754       case EOpUnpackHalf2x16:
755         preString = "unpackHalf2x16(";
756         break;
757 
758       case EOpLength:
759         preString = "length(";
760         break;
761       case EOpNormalize:
762         preString = "normalize(";
763         break;
764 
765       case EOpDFdx:
766         preString = "dFdx(";
767         break;
768       case EOpDFdy:
769         preString = "dFdy(";
770         break;
771       case EOpFwidth:
772         preString = "fwidth(";
773         break;
774 
775       case EOpTranspose:
776         preString = "transpose(";
777         break;
778       case EOpDeterminant:
779         preString = "determinant(";
780         break;
781       case EOpInverse:
782         preString = "inverse(";
783         break;
784 
785       case EOpAny:
786         preString = "any(";
787         break;
788       case EOpAll:
789         preString = "all(";
790         break;
791 
792       default:
793         UNREACHABLE();
794     }
795 
796     if (visit == PreVisit && node->getUseEmulatedFunction())
797         preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
798     writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
799 
800     return true;
801 }
802 
visitTernary(Visit visit,TIntermTernary * node)803 bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
804 {
805     TInfoSinkBase &out = objSink();
806     // Notice two brackets at the beginning and end. The outer ones
807     // encapsulate the whole ternary expression. This preserves the
808     // order of precedence when ternary expressions are used in a
809     // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
810     out << "((";
811     node->getCondition()->traverse(this);
812     out << ") ? (";
813     node->getTrueExpression()->traverse(this);
814     out << ") : (";
815     node->getFalseExpression()->traverse(this);
816     out << "))";
817     return false;
818 }
819 
visitIfElse(Visit visit,TIntermIfElse * node)820 bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
821 {
822     TInfoSinkBase &out = objSink();
823 
824     out << "if (";
825     node->getCondition()->traverse(this);
826     out << ")\n";
827 
828     incrementDepth(node);
829     visitCodeBlock(node->getTrueBlock());
830 
831     if (node->getFalseBlock())
832     {
833         out << "else\n";
834         visitCodeBlock(node->getFalseBlock());
835     }
836     decrementDepth();
837     return false;
838 }
839 
visitSwitch(Visit visit,TIntermSwitch * node)840 bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
841 {
842     if (node->getStatementList())
843     {
844         writeTriplet(visit, "switch (", ") ", nullptr);
845         // The curly braces get written when visiting the statementList aggregate
846     }
847     else
848     {
849         // No statementList, so it won't output curly braces
850         writeTriplet(visit, "switch (", ") {", "}\n");
851     }
852     return true;
853 }
854 
visitCase(Visit visit,TIntermCase * node)855 bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
856 {
857     if (node->hasCondition())
858     {
859         writeTriplet(visit, "case (", nullptr, "):\n");
860         return true;
861     }
862     else
863     {
864         TInfoSinkBase &out = objSink();
865         out << "default:\n";
866         return false;
867     }
868 }
869 
visitBlock(Visit visit,TIntermBlock * node)870 bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
871 {
872     TInfoSinkBase &out = objSink();
873     // Scope the blocks except when at the global scope.
874     if (mDepth > 0)
875     {
876         out << "{\n";
877     }
878 
879     incrementDepth(node);
880     for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
881          iter != node->getSequence()->end(); ++iter)
882     {
883         TIntermNode *curNode = *iter;
884         ASSERT(curNode != nullptr);
885         curNode->traverse(this);
886 
887         if (isSingleStatement(curNode))
888             out << ";\n";
889     }
890     decrementDepth();
891 
892     // Scope the blocks except when at the global scope.
893     if (mDepth > 0)
894     {
895         out << "}\n";
896     }
897     return false;
898 }
899 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)900 bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
901 {
902     TInfoSinkBase &out = objSink();
903 
904     ASSERT(visit == PreVisit);
905     {
906         const TType &type = node->getType();
907         writeVariableType(type);
908         if (type.isArray())
909             out << arrayBrackets(type);
910     }
911 
912     out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
913 
914     incrementDepth(node);
915 
916     // Traverse function parameters.
917     TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
918     ASSERT(params->getOp() == EOpParameters);
919     params->traverse(this);
920 
921     // Traverse function body.
922     visitCodeBlock(node->getBody());
923     decrementDepth();
924 
925     // Fully processed; no need to visit children.
926     return false;
927 }
928 
visitAggregate(Visit visit,TIntermAggregate * node)929 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
930 {
931     bool visitChildren = true;
932     TInfoSinkBase &out = objSink();
933     bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
934     switch (node->getOp())
935     {
936       case EOpPrototype:
937         // Function declaration.
938         ASSERT(visit == PreVisit);
939         {
940             const TType &type = node->getType();
941             writeVariableType(type);
942             if (type.isArray())
943                 out << arrayBrackets(type);
944         }
945 
946         out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
947 
948         out << "(";
949         writeFunctionParameters(*(node->getSequence()));
950         out << ")";
951 
952         visitChildren = false;
953         break;
954       case EOpFunctionCall:
955         // Function call.
956         if (visit == PreVisit)
957             out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
958         else if (visit == InVisit)
959             out << ", ";
960         else
961             out << ")";
962         break;
963       case EOpParameters:
964         // Function parameters.
965         ASSERT(visit == PreVisit);
966         out << "(";
967         writeFunctionParameters(*(node->getSequence()));
968         out << ")";
969         visitChildren = false;
970         break;
971       case EOpInvariantDeclaration:
972         // Invariant declaration.
973         ASSERT(visit == PreVisit);
974         {
975             const TIntermSequence *sequence = node->getSequence();
976             ASSERT(sequence && sequence->size() == 1);
977             const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
978             ASSERT(symbol);
979             out << "invariant " << hashVariableName(symbol->getName());
980         }
981         visitChildren = false;
982         break;
983       case EOpConstructFloat:
984       case EOpConstructVec2:
985       case EOpConstructVec3:
986       case EOpConstructVec4:
987       case EOpConstructBool:
988       case EOpConstructBVec2:
989       case EOpConstructBVec3:
990       case EOpConstructBVec4:
991       case EOpConstructInt:
992       case EOpConstructIVec2:
993       case EOpConstructIVec3:
994       case EOpConstructIVec4:
995       case EOpConstructUInt:
996       case EOpConstructUVec2:
997       case EOpConstructUVec3:
998       case EOpConstructUVec4:
999       case EOpConstructMat2:
1000       case EOpConstructMat2x3:
1001       case EOpConstructMat2x4:
1002       case EOpConstructMat3x2:
1003       case EOpConstructMat3:
1004       case EOpConstructMat3x4:
1005       case EOpConstructMat4x2:
1006       case EOpConstructMat4x3:
1007       case EOpConstructMat4:
1008       case EOpConstructStruct:
1009           writeConstructorTriplet(visit, node->getType());
1010           break;
1011 
1012       case EOpOuterProduct:
1013         writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1014         break;
1015 
1016       case EOpLessThan:
1017         writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1018         break;
1019       case EOpGreaterThan:
1020         writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1021         break;
1022       case EOpLessThanEqual:
1023         writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1024         break;
1025       case EOpGreaterThanEqual:
1026         writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1027         break;
1028       case EOpVectorEqual:
1029         writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1030         break;
1031       case EOpVectorNotEqual:
1032         writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1033         break;
1034 
1035       case EOpMod:
1036         writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1037         break;
1038       case EOpModf:
1039         writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1040         break;
1041       case EOpPow:
1042         writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1043         break;
1044       case EOpAtan:
1045         writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1046         break;
1047       case EOpMin:
1048         writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1049         break;
1050       case EOpMax:
1051         writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1052         break;
1053       case EOpClamp:
1054         writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1055         break;
1056       case EOpMix:
1057         writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1058         break;
1059       case EOpStep:
1060         writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1061         break;
1062       case EOpSmoothStep:
1063         writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1064         break;
1065       case EOpDistance:
1066         writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1067         break;
1068       case EOpDot:
1069         writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1070         break;
1071       case EOpCross:
1072         writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1073         break;
1074       case EOpFaceForward:
1075         writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1076         break;
1077       case EOpReflect:
1078         writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1079         break;
1080       case EOpRefract:
1081         writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1082         break;
1083       case EOpMul:
1084         writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1085         break;
1086 
1087       default:
1088         UNREACHABLE();
1089     }
1090     return visitChildren;
1091 }
1092 
visitDeclaration(Visit visit,TIntermDeclaration * node)1093 bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1094 {
1095     TInfoSinkBase &out = objSink();
1096 
1097     // Variable declaration.
1098     if (visit == PreVisit)
1099     {
1100         const TIntermSequence &sequence = *(node->getSequence());
1101         const TIntermTyped *variable    = sequence.front()->getAsTyped();
1102         writeLayoutQualifier(variable->getType());
1103         writeVariableType(variable->getType());
1104         out << " ";
1105         mDeclaringVariables = true;
1106     }
1107     else if (visit == InVisit)
1108     {
1109         out << ", ";
1110         mDeclaringVariables = true;
1111     }
1112     else
1113     {
1114         mDeclaringVariables = false;
1115     }
1116     return true;
1117 }
1118 
visitLoop(Visit visit,TIntermLoop * node)1119 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
1120 {
1121     TInfoSinkBase &out = objSink();
1122 
1123     incrementDepth(node);
1124 
1125     TLoopType loopType = node->getType();
1126 
1127     // Only for loops can be unrolled
1128     ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1129 
1130     if (loopType == ELoopFor)  // for loop
1131     {
1132         if (!node->getUnrollFlag())
1133         {
1134             out << "for (";
1135             if (node->getInit())
1136                 node->getInit()->traverse(this);
1137             out << "; ";
1138 
1139             if (node->getCondition())
1140                 node->getCondition()->traverse(this);
1141             out << "; ";
1142 
1143             if (node->getExpression())
1144                 node->getExpression()->traverse(this);
1145             out << ")\n";
1146 
1147             visitCodeBlock(node->getBody());
1148         }
1149         else
1150         {
1151             // Need to put a one-iteration loop here to handle break.
1152             TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
1153             TIntermSymbol *indexSymbol =
1154                 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
1155             TString name = hashVariableName(indexSymbol->getName());
1156             out << "for (int " << name << " = 0; "
1157                 << name << " < 1; "
1158                 << "++" << name << ")\n";
1159 
1160             out << "{\n";
1161             mLoopUnrollStack.push(node);
1162             while (mLoopUnrollStack.satisfiesLoopCondition())
1163             {
1164                 visitCodeBlock(node->getBody());
1165                 mLoopUnrollStack.step();
1166             }
1167             mLoopUnrollStack.pop();
1168             out << "}\n";
1169         }
1170     }
1171     else if (loopType == ELoopWhile)  // while loop
1172     {
1173         out << "while (";
1174         ASSERT(node->getCondition() != NULL);
1175         node->getCondition()->traverse(this);
1176         out << ")\n";
1177 
1178         visitCodeBlock(node->getBody());
1179     }
1180     else  // do-while loop
1181     {
1182         ASSERT(loopType == ELoopDoWhile);
1183         out << "do\n";
1184 
1185         visitCodeBlock(node->getBody());
1186 
1187         out << "while (";
1188         ASSERT(node->getCondition() != NULL);
1189         node->getCondition()->traverse(this);
1190         out << ");\n";
1191     }
1192 
1193     decrementDepth();
1194 
1195     // No need to visit children. They have been already processed in
1196     // this function.
1197     return false;
1198 }
1199 
visitBranch(Visit visit,TIntermBranch * node)1200 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1201 {
1202     switch (node->getFlowOp())
1203     {
1204       case EOpKill:
1205         writeTriplet(visit, "discard", NULL, NULL);
1206         break;
1207       case EOpBreak:
1208         writeTriplet(visit, "break", NULL, NULL);
1209         break;
1210       case EOpContinue:
1211         writeTriplet(visit, "continue", NULL, NULL);
1212         break;
1213       case EOpReturn:
1214         writeTriplet(visit, "return ", NULL, NULL);
1215         break;
1216       default:
1217         UNREACHABLE();
1218     }
1219 
1220     return true;
1221 }
1222 
visitCodeBlock(TIntermBlock * node)1223 void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1224 {
1225     TInfoSinkBase &out = objSink();
1226     if (node != NULL)
1227     {
1228         node->traverse(this);
1229         // Single statements not part of a sequence need to be terminated
1230         // with semi-colon.
1231         if (isSingleStatement(node))
1232             out << ";\n";
1233     }
1234     else
1235     {
1236         out << "{\n}\n";  // Empty code block.
1237     }
1238 }
1239 
getTypeName(const TType & type)1240 TString TOutputGLSLBase::getTypeName(const TType &type)
1241 {
1242     if (type.getBasicType() == EbtStruct)
1243         return hashName(TName(type.getStruct()->name()));
1244     else
1245         return type.getBuiltInTypeNameString();
1246 }
1247 
hashName(const TName & name)1248 TString TOutputGLSLBase::hashName(const TName &name)
1249 {
1250     if (name.getString().empty())
1251     {
1252         ASSERT(!name.isInternal());
1253         return name.getString();
1254     }
1255     if (name.isInternal())
1256     {
1257         // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1258         // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1259         // as well.
1260         // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1261         // names don't conflict with user-defined names from WebGL.
1262         return "webgl_angle_" + name.getString();
1263     }
1264     if (mHashFunction == nullptr)
1265     {
1266         return name.getString();
1267     }
1268     NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
1269     if (it != mNameMap.end())
1270         return it->second.c_str();
1271     TString hashedName                 = TIntermTraverser::hash(name.getString(), mHashFunction);
1272     mNameMap[name.getString().c_str()] = hashedName.c_str();
1273     return hashedName;
1274 }
1275 
hashVariableName(const TName & name)1276 TString TOutputGLSLBase::hashVariableName(const TName &name)
1277 {
1278     if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1279         return name.getString();
1280     return hashName(name);
1281 }
1282 
hashFunctionNameIfNeeded(const TName & mangledName)1283 TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
1284 {
1285     TString mangledStr = mangledName.getString();
1286     TString name = TFunction::unmangleName(mangledStr);
1287     if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
1288         return translateTextureFunction(name);
1289     if (mangledName.isInternal())
1290     {
1291         // Internal function names are outputted as-is - they may refer to functions manually added
1292         // to the output shader source that are not included in the AST at all.
1293         return name;
1294     }
1295     else
1296     {
1297         TName nameObj(name);
1298         return hashName(nameObj);
1299     }
1300 }
1301 
structDeclared(const TStructure * structure) const1302 bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
1303 {
1304     ASSERT(structure);
1305     if (structure->name().empty())
1306     {
1307         return false;
1308     }
1309 
1310     return (mDeclaredStructs.count(structure->uniqueId()) > 0);
1311 }
1312 
declareStruct(const TStructure * structure)1313 void TOutputGLSLBase::declareStruct(const TStructure *structure)
1314 {
1315     TInfoSinkBase &out = objSink();
1316 
1317     out << "struct " << hashName(TName(structure->name())) << "{\n";
1318     const TFieldList &fields = structure->fields();
1319     for (size_t i = 0; i < fields.size(); ++i)
1320     {
1321         const TField *field = fields[i];
1322         if (writeVariablePrecision(field->type()->getPrecision()))
1323             out << " ";
1324         out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
1325         if (field->type()->isArray())
1326             out << arrayBrackets(*field->type());
1327         out << ";\n";
1328     }
1329     out << "}";
1330 }
1331 
declareInterfaceBlockLayout(const TInterfaceBlock * interfaceBlock)1332 void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1333 {
1334     TInfoSinkBase &out = objSink();
1335 
1336     out << "layout(";
1337 
1338     switch (interfaceBlock->blockStorage())
1339     {
1340         case EbsUnspecified:
1341         case EbsShared:
1342             // Default block storage is shared.
1343             out << "shared";
1344             break;
1345 
1346         case EbsPacked:
1347             out << "packed";
1348             break;
1349 
1350         case EbsStd140:
1351             out << "std140";
1352             break;
1353 
1354         default:
1355             UNREACHABLE();
1356             break;
1357     }
1358 
1359     out << ", ";
1360 
1361     switch (interfaceBlock->matrixPacking())
1362     {
1363         case EmpUnspecified:
1364         case EmpColumnMajor:
1365             // Default matrix packing is column major.
1366             out << "column_major";
1367             break;
1368 
1369         case EmpRowMajor:
1370             out << "row_major";
1371             break;
1372 
1373         default:
1374             UNREACHABLE();
1375             break;
1376     }
1377 
1378     out << ") ";
1379 }
1380 
declareInterfaceBlock(const TInterfaceBlock * interfaceBlock)1381 void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1382 {
1383     TInfoSinkBase &out = objSink();
1384 
1385     out << hashName(TName(interfaceBlock->name())) << "{\n";
1386     const TFieldList &fields = interfaceBlock->fields();
1387     for (size_t i = 0; i < fields.size(); ++i)
1388     {
1389         const TField *field = fields[i];
1390         if (writeVariablePrecision(field->type()->getPrecision()))
1391             out << " ";
1392         out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
1393         if (field->type()->isArray())
1394             out << arrayBrackets(*field->type());
1395         out << ";\n";
1396     }
1397     out << "}";
1398 }
1399 
1400 }  // namespace sh
1401