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