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