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