tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OutputGLSLBase.cpp (42551B)


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