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