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