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