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