tor-browser

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

OutputHLSL.cpp (122598B)


      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/OutputHLSL.h"
      8 
      9 #include <stdio.h>
     10 #include <algorithm>
     11 #include <cfloat>
     12 
     13 #include "common/angleutils.h"
     14 #include "common/debug.h"
     15 #include "common/utilities.h"
     16 #include "compiler/translator/AtomicCounterFunctionHLSL.h"
     17 #include "compiler/translator/BuiltInFunctionEmulator.h"
     18 #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
     19 #include "compiler/translator/ImageFunctionHLSL.h"
     20 #include "compiler/translator/InfoSink.h"
     21 #include "compiler/translator/ResourcesHLSL.h"
     22 #include "compiler/translator/StructureHLSL.h"
     23 #include "compiler/translator/TextureFunctionHLSL.h"
     24 #include "compiler/translator/TranslatorHLSL.h"
     25 #include "compiler/translator/UtilsHLSL.h"
     26 #include "compiler/translator/blocklayout.h"
     27 #include "compiler/translator/tree_ops/d3d/RemoveSwitchFallThrough.h"
     28 #include "compiler/translator/tree_util/FindSymbolNode.h"
     29 #include "compiler/translator/tree_util/NodeSearch.h"
     30 #include "compiler/translator/util.h"
     31 
     32 namespace sh
     33 {
     34 
     35 namespace
     36 {
     37 
     38 constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
     39 
     40 TString ArrayHelperFunctionName(const char *prefix, const TType &type)
     41 {
     42    TStringStream fnName = sh::InitializeStream<TStringStream>();
     43    fnName << prefix << "_";
     44    if (type.isArray())
     45    {
     46        for (unsigned int arraySize : type.getArraySizes())
     47        {
     48            fnName << arraySize << "_";
     49        }
     50    }
     51    fnName << TypeString(type);
     52    return fnName.str();
     53 }
     54 
     55 bool IsDeclarationWrittenOut(TIntermDeclaration *node)
     56 {
     57    TIntermSequence *sequence = node->getSequence();
     58    TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
     59    ASSERT(sequence->size() == 1);
     60    ASSERT(variable);
     61    return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
     62            variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared);
     63 }
     64 
     65 bool IsInStd140UniformBlock(TIntermTyped *node)
     66 {
     67    TIntermBinary *binaryNode = node->getAsBinaryNode();
     68 
     69    if (binaryNode)
     70    {
     71        return IsInStd140UniformBlock(binaryNode->getLeft());
     72    }
     73 
     74    const TType &type = node->getType();
     75 
     76    if (type.getQualifier() == EvqUniform)
     77    {
     78        // determine if we are in the standard layout
     79        const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
     80        if (interfaceBlock)
     81        {
     82            return (interfaceBlock->blockStorage() == EbsStd140);
     83        }
     84    }
     85 
     86    return false;
     87 }
     88 
     89 const TInterfaceBlock *GetInterfaceBlockOfUniformBlockNearestIndexOperator(TIntermTyped *node)
     90 {
     91    const TIntermBinary *binaryNode = node->getAsBinaryNode();
     92    if (binaryNode)
     93    {
     94        if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
     95        {
     96            return binaryNode->getLeft()->getType().getInterfaceBlock();
     97        }
     98    }
     99 
    100    const TIntermSymbol *symbolNode = node->getAsSymbolNode();
    101    if (symbolNode)
    102    {
    103        const TVariable &variable = symbolNode->variable();
    104        const TType &variableType = variable.getType();
    105 
    106        if (variableType.getQualifier() == EvqUniform &&
    107            variable.symbolType() == SymbolType::UserDefined)
    108        {
    109            return variableType.getInterfaceBlock();
    110        }
    111    }
    112 
    113    return nullptr;
    114 }
    115 
    116 const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op)
    117 {
    118    switch (op)
    119    {
    120        case EOpAtomicAdd:
    121            return "InterlockedAdd(";
    122        case EOpAtomicMin:
    123            return "InterlockedMin(";
    124        case EOpAtomicMax:
    125            return "InterlockedMax(";
    126        case EOpAtomicAnd:
    127            return "InterlockedAnd(";
    128        case EOpAtomicOr:
    129            return "InterlockedOr(";
    130        case EOpAtomicXor:
    131            return "InterlockedXor(";
    132        case EOpAtomicExchange:
    133            return "InterlockedExchange(";
    134        case EOpAtomicCompSwap:
    135            return "InterlockedCompareExchange(";
    136        default:
    137            UNREACHABLE();
    138            return "";
    139    }
    140 }
    141 
    142 bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node)
    143 {
    144    TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate();
    145    if (aggregateNode == nullptr)
    146    {
    147        return false;
    148    }
    149 
    150    if (node.getOp() == EOpAssign && BuiltInGroup::IsAtomicMemory(aggregateNode->getOp()))
    151    {
    152        return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped());
    153    }
    154 
    155    return false;
    156 }
    157 
    158 const char *kZeros       = "_ANGLE_ZEROS_";
    159 constexpr int kZeroCount = 256;
    160 std::string DefineZeroArray()
    161 {
    162    std::stringstream ss = sh::InitializeStream<std::stringstream>();
    163    // For 'static', if the declaration does not include an initializer, the value is set to zero.
    164    // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax
    165    ss << "static uint " << kZeros << "[" << kZeroCount << "];\n";
    166    return ss.str();
    167 }
    168 
    169 std::string GetZeroInitializer(size_t size)
    170 {
    171    std::stringstream ss = sh::InitializeStream<std::stringstream>();
    172    size_t quotient      = size / kZeroCount;
    173    size_t reminder      = size % kZeroCount;
    174 
    175    for (size_t i = 0; i < quotient; ++i)
    176    {
    177        if (i != 0)
    178        {
    179            ss << ", ";
    180        }
    181        ss << kZeros;
    182    }
    183 
    184    for (size_t i = 0; i < reminder; ++i)
    185    {
    186        if (quotient != 0 || i != 0)
    187        {
    188            ss << ", ";
    189        }
    190        ss << "0";
    191    }
    192 
    193    return ss.str();
    194 }
    195 
    196 }  // anonymous namespace
    197 
    198 TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock,
    199                                   const TVariable *aInstanceVariable)
    200    : block(aBlock), instanceVariable(aInstanceVariable)
    201 {}
    202 
    203 bool OutputHLSL::needStructMapping(TIntermTyped *node)
    204 {
    205    ASSERT(node->getBasicType() == EbtStruct);
    206    for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
    207    {
    208        TIntermNode *ancestor               = getAncestorNode(n);
    209        const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
    210        if (ancestorBinary)
    211        {
    212            switch (ancestorBinary->getOp())
    213            {
    214                case EOpIndexDirectStruct:
    215                {
    216                    const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
    217                    const TIntermConstantUnion *index =
    218                        ancestorBinary->getRight()->getAsConstantUnion();
    219                    const TField *field = structure->fields()[index->getIConst(0)];
    220                    if (field->type()->getStruct() == nullptr)
    221                    {
    222                        return false;
    223                    }
    224                    break;
    225                }
    226                case EOpIndexDirect:
    227                case EOpIndexIndirect:
    228                    break;
    229                default:
    230                    return true;
    231            }
    232        }
    233        else
    234        {
    235            const TIntermAggregate *ancestorAggregate = ancestor->getAsAggregate();
    236            if (ancestorAggregate)
    237            {
    238                return true;
    239            }
    240            return false;
    241        }
    242    }
    243    return true;
    244 }
    245 
    246 void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
    247 {
    248    // This is known not to work for NaN on all drivers but make the best effort to output NaNs
    249    // regardless.
    250    if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
    251        mOutputType == SH_HLSL_4_1_OUTPUT)
    252    {
    253        out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
    254    }
    255    else
    256    {
    257        out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
    258    }
    259 }
    260 
    261 void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
    262 {
    263    ASSERT(constUnion != nullptr);
    264    switch (constUnion->getType())
    265    {
    266        case EbtFloat:
    267            writeFloat(out, constUnion->getFConst());
    268            break;
    269        case EbtInt:
    270            out << constUnion->getIConst();
    271            break;
    272        case EbtUInt:
    273            out << constUnion->getUConst();
    274            break;
    275        case EbtBool:
    276            out << constUnion->getBConst();
    277            break;
    278        default:
    279            UNREACHABLE();
    280    }
    281 }
    282 
    283 const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
    284                                                          const TConstantUnion *const constUnion,
    285                                                          const size_t size)
    286 {
    287    const TConstantUnion *constUnionIterated = constUnion;
    288    for (size_t i = 0; i < size; i++, constUnionIterated++)
    289    {
    290        writeSingleConstant(out, constUnionIterated);
    291 
    292        if (i != size - 1)
    293        {
    294            out << ", ";
    295        }
    296    }
    297    return constUnionIterated;
    298 }
    299 
    300 OutputHLSL::OutputHLSL(sh::GLenum shaderType,
    301                       ShShaderSpec shaderSpec,
    302                       int shaderVersion,
    303                       const TExtensionBehavior &extensionBehavior,
    304                       const char *sourcePath,
    305                       ShShaderOutput outputType,
    306                       int numRenderTargets,
    307                       int maxDualSourceDrawBuffers,
    308                       const std::vector<ShaderVariable> &uniforms,
    309                       const ShCompileOptions &compileOptions,
    310                       sh::WorkGroupSize workGroupSize,
    311                       TSymbolTable *symbolTable,
    312                       PerformanceDiagnostics *perfDiagnostics,
    313                       const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
    314                       const std::vector<InterfaceBlock> &shaderStorageBlocks,
    315                       bool isEarlyFragmentTestsSpecified)
    316    : TIntermTraverser(true, true, true, symbolTable),
    317      mShaderType(shaderType),
    318      mShaderSpec(shaderSpec),
    319      mShaderVersion(shaderVersion),
    320      mExtensionBehavior(extensionBehavior),
    321      mSourcePath(sourcePath),
    322      mOutputType(outputType),
    323      mCompileOptions(compileOptions),
    324      mInsideFunction(false),
    325      mInsideMain(false),
    326      mUniformBlockOptimizedMap(uniformBlockOptimizedMap),
    327      mNumRenderTargets(numRenderTargets),
    328      mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
    329      mCurrentFunctionMetadata(nullptr),
    330      mWorkGroupSize(workGroupSize),
    331      mPerfDiagnostics(perfDiagnostics),
    332      mIsEarlyFragmentTestsSpecified(isEarlyFragmentTestsSpecified),
    333      mNeedStructMapping(false)
    334 {
    335    mUsesFragColor        = false;
    336    mUsesFragData         = false;
    337    mUsesDepthRange       = false;
    338    mUsesFragCoord        = false;
    339    mUsesPointCoord       = false;
    340    mUsesFrontFacing      = false;
    341    mUsesHelperInvocation = false;
    342    mUsesPointSize        = false;
    343    mUsesInstanceID       = false;
    344    mHasMultiviewExtensionEnabled =
    345        IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview) ||
    346        IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2);
    347    mUsesViewID                  = false;
    348    mUsesVertexID                = false;
    349    mUsesFragDepth               = false;
    350    mUsesNumWorkGroups           = false;
    351    mUsesWorkGroupID             = false;
    352    mUsesLocalInvocationID       = false;
    353    mUsesGlobalInvocationID      = false;
    354    mUsesLocalInvocationIndex    = false;
    355    mUsesXor                     = false;
    356    mUsesDiscardRewriting        = false;
    357    mUsesNestedBreak             = false;
    358    mRequiresIEEEStrictCompiling = false;
    359    mUseZeroArray                = false;
    360    mUsesSecondaryColor          = false;
    361 
    362    mUniqueIndex = 0;
    363 
    364    mOutputLod0Function      = false;
    365    mInsideDiscontinuousLoop = false;
    366    mNestedLoopDepth         = 0;
    367 
    368    mExcessiveLoopIndex = nullptr;
    369 
    370    mStructureHLSL       = new StructureHLSL;
    371    mTextureFunctionHLSL = new TextureFunctionHLSL;
    372    mImageFunctionHLSL   = new ImageFunctionHLSL;
    373    mAtomicCounterFunctionHLSL =
    374        new AtomicCounterFunctionHLSL(compileOptions.forceAtomicValueResolution);
    375 
    376    unsigned int firstUniformRegister = compileOptions.skipD3DConstantRegisterZero ? 1u : 0u;
    377    mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
    378 
    379    if (mOutputType == SH_HLSL_3_0_OUTPUT)
    380    {
    381        // Fragment shaders need dx_DepthRange, dx_ViewCoords, dx_DepthFront,
    382        // and dx_FragCoordOffset.
    383        // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and
    384        // dx_ViewAdjust.
    385        if (mShaderType == GL_VERTEX_SHADER)
    386        {
    387            mResourcesHLSL->reserveUniformRegisters(3);
    388        }
    389        else
    390        {
    391            mResourcesHLSL->reserveUniformRegisters(4);
    392        }
    393    }
    394 
    395    // Reserve registers for the default uniform block and driver constants
    396    mResourcesHLSL->reserveUniformBlockRegisters(2);
    397 
    398    mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, mResourcesHLSL, shaderStorageBlocks);
    399 }
    400 
    401 OutputHLSL::~OutputHLSL()
    402 {
    403    SafeDelete(mSSBOOutputHLSL);
    404    SafeDelete(mStructureHLSL);
    405    SafeDelete(mResourcesHLSL);
    406    SafeDelete(mTextureFunctionHLSL);
    407    SafeDelete(mImageFunctionHLSL);
    408    SafeDelete(mAtomicCounterFunctionHLSL);
    409    for (auto &eqFunction : mStructEqualityFunctions)
    410    {
    411        SafeDelete(eqFunction);
    412    }
    413    for (auto &eqFunction : mArrayEqualityFunctions)
    414    {
    415        SafeDelete(eqFunction);
    416    }
    417 }
    418 
    419 void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
    420 {
    421    BuiltInFunctionEmulator builtInFunctionEmulator;
    422    InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
    423    if (mCompileOptions.emulateIsnanFloatFunction)
    424    {
    425        InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
    426                                                           mShaderVersion);
    427    }
    428 
    429    builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot);
    430 
    431    // Now that we are done changing the AST, do the analyses need for HLSL generation
    432    CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
    433    ASSERT(success == CallDAG::INITDAG_SUCCESS);
    434    mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
    435 
    436    const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot);
    437    // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in
    438    // the shader code. When we add shader storage blocks we might also consider an alternative
    439    // solution, since the struct mapping won't work very well for shader storage blocks.
    440 
    441    // Output the body and footer first to determine what has to go in the header
    442    mInfoSinkStack.push(&mBody);
    443    treeRoot->traverse(this);
    444    mInfoSinkStack.pop();
    445 
    446    mInfoSinkStack.push(&mFooter);
    447    mInfoSinkStack.pop();
    448 
    449    mInfoSinkStack.push(&mHeader);
    450    header(mHeader, std140Structs, &builtInFunctionEmulator);
    451    mInfoSinkStack.pop();
    452 
    453    objSink << mHeader.c_str();
    454    objSink << mBody.c_str();
    455    objSink << mFooter.c_str();
    456 
    457    builtInFunctionEmulator.cleanup();
    458 }
    459 
    460 const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const
    461 {
    462    return mResourcesHLSL->getShaderStorageBlockRegisterMap();
    463 }
    464 
    465 const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const
    466 {
    467    return mResourcesHLSL->getUniformBlockRegisterMap();
    468 }
    469 
    470 const std::map<std::string, bool> &OutputHLSL::getUniformBlockUseStructuredBufferMap() const
    471 {
    472    return mResourcesHLSL->getUniformBlockUseStructuredBufferMap();
    473 }
    474 
    475 const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
    476 {
    477    return mResourcesHLSL->getUniformRegisterMap();
    478 }
    479 
    480 unsigned int OutputHLSL::getReadonlyImage2DRegisterIndex() const
    481 {
    482    return mResourcesHLSL->getReadonlyImage2DRegisterIndex();
    483 }
    484 
    485 unsigned int OutputHLSL::getImage2DRegisterIndex() const
    486 {
    487    return mResourcesHLSL->getImage2DRegisterIndex();
    488 }
    489 
    490 const std::set<std::string> &OutputHLSL::getUsedImage2DFunctionNames() const
    491 {
    492    return mImageFunctionHLSL->getUsedImage2DFunctionNames();
    493 }
    494 
    495 TString OutputHLSL::structInitializerString(int indent,
    496                                            const TType &type,
    497                                            const TString &name) const
    498 {
    499    TString init;
    500 
    501    TString indentString;
    502    for (int spaces = 0; spaces < indent; spaces++)
    503    {
    504        indentString += "    ";
    505    }
    506 
    507    if (type.isArray())
    508    {
    509        init += indentString + "{\n";
    510        for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
    511        {
    512            TStringStream indexedString = sh::InitializeStream<TStringStream>();
    513            indexedString << name << "[" << arrayIndex << "]";
    514            TType elementType = type;
    515            elementType.toArrayElementType();
    516            init += structInitializerString(indent + 1, elementType, indexedString.str());
    517            if (arrayIndex < type.getOutermostArraySize() - 1)
    518            {
    519                init += ",";
    520            }
    521            init += "\n";
    522        }
    523        init += indentString + "}";
    524    }
    525    else if (type.getBasicType() == EbtStruct)
    526    {
    527        init += indentString + "{\n";
    528        const TStructure &structure = *type.getStruct();
    529        const TFieldList &fields    = structure.fields();
    530        for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
    531        {
    532            const TField &field      = *fields[fieldIndex];
    533            const TString &fieldName = name + "." + Decorate(field.name());
    534            const TType &fieldType   = *field.type();
    535 
    536            init += structInitializerString(indent + 1, fieldType, fieldName);
    537            if (fieldIndex < fields.size() - 1)
    538            {
    539                init += ",";
    540            }
    541            init += "\n";
    542        }
    543        init += indentString + "}";
    544    }
    545    else
    546    {
    547        init += indentString + name;
    548    }
    549 
    550    return init;
    551 }
    552 
    553 TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const
    554 {
    555    TString mappedStructs;
    556 
    557    for (auto &mappedStruct : std140Structs)
    558    {
    559        const TInterfaceBlock *interfaceBlock =
    560            mappedStruct.blockDeclarator->getType().getInterfaceBlock();
    561        TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier();
    562        switch (qualifier)
    563        {
    564            case EvqUniform:
    565                if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
    566                {
    567                    continue;
    568                }
    569                break;
    570            case EvqBuffer:
    571                continue;
    572            default:
    573                UNREACHABLE();
    574                return mappedStructs;
    575        }
    576 
    577        unsigned int instanceCount = 1u;
    578        bool isInstanceArray       = mappedStruct.blockDeclarator->isArray();
    579        if (isInstanceArray)
    580        {
    581            instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize();
    582        }
    583 
    584        for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount;
    585             ++instanceArrayIndex)
    586        {
    587            TString originalName;
    588            TString mappedName("map");
    589 
    590            if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty)
    591            {
    592                const ImmutableString &instanceName =
    593                    mappedStruct.blockDeclarator->variable().name();
    594                unsigned int instanceStringArrayIndex = GL_INVALID_INDEX;
    595                if (isInstanceArray)
    596                    instanceStringArrayIndex = instanceArrayIndex;
    597                TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString(
    598                    instanceName, instanceStringArrayIndex);
    599                originalName += instanceString;
    600                mappedName += instanceString;
    601                originalName += ".";
    602                mappedName += "_";
    603            }
    604 
    605            TString fieldName = Decorate(mappedStruct.field->name());
    606            originalName += fieldName;
    607            mappedName += fieldName;
    608 
    609            TType *structType = mappedStruct.field->type();
    610            mappedStructs +=
    611                "static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
    612 
    613            if (structType->isArray())
    614            {
    615                mappedStructs += ArrayString(*mappedStruct.field->type()).data();
    616            }
    617 
    618            mappedStructs += " =\n";
    619            mappedStructs += structInitializerString(0, *structType, originalName);
    620            mappedStructs += ";\n";
    621        }
    622    }
    623    return mappedStructs;
    624 }
    625 
    626 void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const
    627 {
    628    for (const auto &attribute : mReferencedAttributes)
    629    {
    630        const TType &type           = attribute.second->getType();
    631        const ImmutableString &name = attribute.second->name();
    632 
    633        out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = "
    634            << zeroInitializer(type) << ";\n";
    635    }
    636 }
    637 
    638 void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const
    639 {
    640    for (const auto &varying : mReferencedVaryings)
    641    {
    642        const TType &type = varying.second->getType();
    643 
    644        // Program linking depends on this exact format
    645        out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type)
    646            << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = "
    647            << zeroInitializer(type) << ";\n";
    648    }
    649 }
    650 
    651 void OutputHLSL::header(TInfoSinkBase &out,
    652                        const std::vector<MappedStruct> &std140Structs,
    653                        const BuiltInFunctionEmulator *builtInFunctionEmulator) const
    654 {
    655    TString mappedStructs;
    656    if (mNeedStructMapping)
    657    {
    658        mappedStructs = generateStructMapping(std140Structs);
    659    }
    660 
    661    // Suppress some common warnings:
    662    // 3556 : Integer divides might be much slower, try using uints if possible.
    663    // 3571 : The pow(f, e) intrinsic function won't work for negative f, use abs(f) or
    664    //        conditionally handle negative values if you expect them.
    665    out << "#pragma warning( disable: 3556 3571 )\n";
    666 
    667    out << mStructureHLSL->structsHeader();
    668 
    669    mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
    670    out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks, mUniformBlockOptimizedMap);
    671    mSSBOOutputHLSL->writeShaderStorageBlocksHeader(mShaderType, out);
    672 
    673    if (!mEqualityFunctions.empty())
    674    {
    675        out << "\n// Equality functions\n\n";
    676        for (const auto &eqFunction : mEqualityFunctions)
    677        {
    678            out << eqFunction->functionDefinition << "\n";
    679        }
    680    }
    681    if (!mArrayAssignmentFunctions.empty())
    682    {
    683        out << "\n// Assignment functions\n\n";
    684        for (const auto &assignmentFunction : mArrayAssignmentFunctions)
    685        {
    686            out << assignmentFunction.functionDefinition << "\n";
    687        }
    688    }
    689    if (!mArrayConstructIntoFunctions.empty())
    690    {
    691        out << "\n// Array constructor functions\n\n";
    692        for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
    693        {
    694            out << constructIntoFunction.functionDefinition << "\n";
    695        }
    696    }
    697 
    698    if (mUsesDiscardRewriting)
    699    {
    700        out << "#define ANGLE_USES_DISCARD_REWRITING\n";
    701    }
    702 
    703    if (mUsesNestedBreak)
    704    {
    705        out << "#define ANGLE_USES_NESTED_BREAK\n";
    706    }
    707 
    708    if (mRequiresIEEEStrictCompiling)
    709    {
    710        out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
    711    }
    712 
    713    out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
    714           "#define LOOP [loop]\n"
    715           "#define FLATTEN [flatten]\n"
    716           "#else\n"
    717           "#define LOOP\n"
    718           "#define FLATTEN\n"
    719           "#endif\n";
    720 
    721    // array stride for atomic counter buffers is always 4 per original extension
    722    // ARB_shader_atomic_counters and discussion on
    723    // https://github.com/KhronosGroup/OpenGL-API/issues/5
    724    out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n";
    725 
    726    if (mUseZeroArray)
    727    {
    728        out << DefineZeroArray() << "\n";
    729    }
    730 
    731    if (mShaderType == GL_FRAGMENT_SHADER)
    732    {
    733        const bool usingMRTExtension =
    734            IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
    735        const bool usingBFEExtension =
    736            IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_blend_func_extended);
    737 
    738        out << "// Varyings\n";
    739        writeReferencedVaryings(out);
    740        out << "\n";
    741 
    742        if ((IsDesktopGLSpec(mShaderSpec) && mShaderVersion >= 130) ||
    743            (!IsDesktopGLSpec(mShaderSpec) && mShaderVersion >= 300))
    744        {
    745            for (const auto &outputVariable : mReferencedOutputVariables)
    746            {
    747                const ImmutableString &variableName = outputVariable.second->name();
    748                const TType &variableType           = outputVariable.second->getType();
    749 
    750                out << "static " << TypeString(variableType) << " out_" << variableName
    751                    << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n";
    752            }
    753        }
    754        else
    755        {
    756            const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
    757 
    758            out << "static float4 gl_Color[" << numColorValues
    759                << "] =\n"
    760                   "{\n";
    761            for (unsigned int i = 0; i < numColorValues; i++)
    762            {
    763                out << "    float4(0, 0, 0, 0)";
    764                if (i + 1 != numColorValues)
    765                {
    766                    out << ",";
    767                }
    768                out << "\n";
    769            }
    770 
    771            out << "};\n";
    772 
    773            if (usingBFEExtension && mUsesSecondaryColor)
    774            {
    775                out << "static float4 gl_SecondaryColor[" << mMaxDualSourceDrawBuffers
    776                    << "] = \n"
    777                       "{\n";
    778                for (int i = 0; i < mMaxDualSourceDrawBuffers; i++)
    779                {
    780                    out << "    float4(0, 0, 0, 0)";
    781                    if (i + 1 != mMaxDualSourceDrawBuffers)
    782                    {
    783                        out << ",";
    784                    }
    785                    out << "\n";
    786                }
    787                out << "};\n";
    788            }
    789        }
    790 
    791        if (mUsesFragDepth)
    792        {
    793            out << "static float gl_Depth = 0.0;\n";
    794        }
    795 
    796        if (mUsesFragCoord)
    797        {
    798            out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
    799        }
    800 
    801        if (mUsesPointCoord)
    802        {
    803            out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
    804        }
    805 
    806        if (mUsesFrontFacing)
    807        {
    808            out << "static bool gl_FrontFacing = false;\n";
    809        }
    810 
    811        if (mUsesHelperInvocation)
    812        {
    813            out << "static bool gl_HelperInvocation = false;\n";
    814        }
    815 
    816        out << "\n";
    817 
    818        if (mUsesDepthRange)
    819        {
    820            out << "struct gl_DepthRangeParameters\n"
    821                   "{\n"
    822                   "    float near;\n"
    823                   "    float far;\n"
    824                   "    float diff;\n"
    825                   "};\n"
    826                   "\n";
    827        }
    828 
    829        if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    830        {
    831            out << "cbuffer DriverConstants : register(b1)\n"
    832                   "{\n";
    833 
    834            if (mUsesDepthRange)
    835            {
    836                out << "    float3 dx_DepthRange : packoffset(c0);\n";
    837            }
    838 
    839            if (mUsesFragCoord)
    840            {
    841                out << "    float4 dx_ViewCoords : packoffset(c1);\n";
    842                out << "    float2 dx_FragCoordOffset : packoffset(c3);\n";
    843            }
    844 
    845            if (mUsesFragCoord || mUsesFrontFacing)
    846            {
    847                out << "    float3 dx_DepthFront : packoffset(c2);\n";
    848            }
    849 
    850            if (mUsesFragCoord)
    851            {
    852                // dx_ViewScale is only used in the fragment shader to correct
    853                // the value for glFragCoord if necessary
    854                out << "    float2 dx_ViewScale : packoffset(c3.z);\n";
    855            }
    856 
    857            if (mHasMultiviewExtensionEnabled)
    858            {
    859                // We have to add a value which we can use to keep track of which multi-view code
    860                // path is to be selected in the GS.
    861                out << "    float multiviewSelectViewportIndex : packoffset(c4.x);\n";
    862            }
    863 
    864            if (mOutputType == SH_HLSL_4_1_OUTPUT)
    865            {
    866                unsigned int registerIndex = 5;
    867                mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
    868                // Sampler metadata struct must be two 4-vec, 32 bytes.
    869                registerIndex += mResourcesHLSL->getSamplerCount() * 2;
    870                mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
    871            }
    872 
    873            out << "};\n";
    874 
    875            if (mOutputType == SH_HLSL_4_1_OUTPUT && mResourcesHLSL->hasImages())
    876            {
    877                out << kImage2DFunctionString << "\n";
    878            }
    879        }
    880        else
    881        {
    882            if (mUsesDepthRange)
    883            {
    884                out << "uniform float3 dx_DepthRange : register(c0);";
    885            }
    886 
    887            if (mUsesFragCoord)
    888            {
    889                out << "uniform float4 dx_ViewCoords : register(c1);\n";
    890            }
    891 
    892            if (mUsesFragCoord || mUsesFrontFacing)
    893            {
    894                out << "uniform float3 dx_DepthFront : register(c2);\n";
    895                out << "uniform float2 dx_FragCoordOffset : register(c3);\n";
    896            }
    897        }
    898 
    899        out << "\n";
    900 
    901        if (mUsesDepthRange)
    902        {
    903            out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
    904                   "dx_DepthRange.y, dx_DepthRange.z};\n"
    905                   "\n";
    906        }
    907 
    908        if (usingMRTExtension && mNumRenderTargets > 1)
    909        {
    910            out << "#define GL_USES_MRT\n";
    911        }
    912 
    913        if (mUsesFragColor)
    914        {
    915            out << "#define GL_USES_FRAG_COLOR\n";
    916        }
    917 
    918        if (mUsesFragData)
    919        {
    920            out << "#define GL_USES_FRAG_DATA\n";
    921        }
    922 
    923        if (mShaderVersion < 300 && usingBFEExtension && mUsesSecondaryColor)
    924        {
    925            out << "#define GL_USES_SECONDARY_COLOR\n";
    926        }
    927    }
    928    else if (mShaderType == GL_VERTEX_SHADER)
    929    {
    930        out << "// Attributes\n";
    931        writeReferencedAttributes(out);
    932        out << "\n"
    933               "static float4 gl_Position = float4(0, 0, 0, 0);\n";
    934 
    935        if (mUsesPointSize)
    936        {
    937            out << "static float gl_PointSize = float(1);\n";
    938        }
    939 
    940        if (mUsesInstanceID)
    941        {
    942            out << "static int gl_InstanceID;";
    943        }
    944 
    945        if (mUsesVertexID)
    946        {
    947            out << "static int gl_VertexID;";
    948        }
    949 
    950        out << "\n"
    951               "// Varyings\n";
    952        writeReferencedVaryings(out);
    953        out << "\n";
    954 
    955        if (mUsesDepthRange)
    956        {
    957            out << "struct gl_DepthRangeParameters\n"
    958                   "{\n"
    959                   "    float near;\n"
    960                   "    float far;\n"
    961                   "    float diff;\n"
    962                   "};\n"
    963                   "\n";
    964        }
    965 
    966        if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    967        {
    968            out << "cbuffer DriverConstants : register(b1)\n"
    969                   "{\n";
    970 
    971            if (mUsesDepthRange)
    972            {
    973                out << "    float3 dx_DepthRange : packoffset(c0);\n";
    974            }
    975 
    976            // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
    977            // shaders. However, we declare it for all shaders (including Feature Level 10+).
    978            // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
    979            // if it's unused.
    980            out << "    float4 dx_ViewAdjust : packoffset(c1);\n";
    981            out << "    float2 dx_ViewCoords : packoffset(c2);\n";
    982            out << "    float2 dx_ViewScale  : packoffset(c3);\n";
    983 
    984            if (mHasMultiviewExtensionEnabled)
    985            {
    986                // We have to add a value which we can use to keep track of which multi-view code
    987                // path is to be selected in the GS.
    988                out << "    float multiviewSelectViewportIndex : packoffset(c3.z);\n";
    989            }
    990 
    991            out << "    float clipControlOrigin : packoffset(c3.w);\n";
    992            out << "    float clipControlZeroToOne : packoffset(c4);\n";
    993 
    994            if (mOutputType == SH_HLSL_4_1_OUTPUT)
    995            {
    996                mResourcesHLSL->samplerMetadataUniforms(out, 5);
    997            }
    998 
    999            if (mUsesVertexID)
   1000            {
   1001                out << "    uint dx_VertexID : packoffset(c4.y);\n";
   1002            }
   1003 
   1004            out << "};\n"
   1005                   "\n";
   1006        }
   1007        else
   1008        {
   1009            if (mUsesDepthRange)
   1010            {
   1011                out << "uniform float3 dx_DepthRange : register(c0);\n";
   1012            }
   1013 
   1014            out << "uniform float4 dx_ViewAdjust : register(c1);\n";
   1015            out << "uniform float2 dx_ViewCoords : register(c2);\n";
   1016 
   1017            out << "static const float clipControlOrigin = -1.0f;\n";
   1018            out << "static const float clipControlZeroToOne = 0.0f;\n";
   1019 
   1020            out << "\n";
   1021        }
   1022 
   1023        if (mUsesDepthRange)
   1024        {
   1025            out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, "
   1026                   "dx_DepthRange.y, dx_DepthRange.z};\n"
   1027                   "\n";
   1028        }
   1029    }
   1030    else  // Compute shader
   1031    {
   1032        ASSERT(mShaderType == GL_COMPUTE_SHADER);
   1033 
   1034        out << "cbuffer DriverConstants : register(b1)\n"
   1035               "{\n";
   1036        if (mUsesNumWorkGroups)
   1037        {
   1038            out << "    uint3 gl_NumWorkGroups : packoffset(c0);\n";
   1039        }
   1040        ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
   1041        unsigned int registerIndex = 1;
   1042        mResourcesHLSL->samplerMetadataUniforms(out, registerIndex);
   1043        // Sampler metadata struct must be two 4-vec, 32 bytes.
   1044        registerIndex += mResourcesHLSL->getSamplerCount() * 2;
   1045        mResourcesHLSL->imageMetadataUniforms(out, registerIndex);
   1046        out << "};\n";
   1047 
   1048        out << kImage2DFunctionString << "\n";
   1049 
   1050        std::ostringstream systemValueDeclaration  = sh::InitializeStream<std::ostringstream>();
   1051        std::ostringstream glBuiltinInitialization = sh::InitializeStream<std::ostringstream>();
   1052 
   1053        systemValueDeclaration << "\nstruct CS_INPUT\n{\n";
   1054        glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n"
   1055                                << "{\n";
   1056 
   1057        if (mUsesWorkGroupID)
   1058        {
   1059            out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
   1060            systemValueDeclaration << "    uint3 dx_WorkGroupID : "
   1061                                   << "SV_GroupID;\n";
   1062            glBuiltinInitialization << "    gl_WorkGroupID = input.dx_WorkGroupID;\n";
   1063        }
   1064 
   1065        if (mUsesLocalInvocationID)
   1066        {
   1067            out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
   1068            systemValueDeclaration << "    uint3 dx_LocalInvocationID : "
   1069                                   << "SV_GroupThreadID;\n";
   1070            glBuiltinInitialization << "    gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
   1071        }
   1072 
   1073        if (mUsesGlobalInvocationID)
   1074        {
   1075            out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
   1076            systemValueDeclaration << "    uint3 dx_GlobalInvocationID : "
   1077                                   << "SV_DispatchThreadID;\n";
   1078            glBuiltinInitialization << "    gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
   1079        }
   1080 
   1081        if (mUsesLocalInvocationIndex)
   1082        {
   1083            out << "static uint gl_LocalInvocationIndex = uint(0);\n";
   1084            systemValueDeclaration << "    uint dx_LocalInvocationIndex : "
   1085                                   << "SV_GroupIndex;\n";
   1086            glBuiltinInitialization
   1087                << "    gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
   1088        }
   1089 
   1090        systemValueDeclaration << "};\n\n";
   1091        glBuiltinInitialization << "};\n\n";
   1092 
   1093        out << systemValueDeclaration.str();
   1094        out << glBuiltinInitialization.str();
   1095    }
   1096 
   1097    if (!mappedStructs.empty())
   1098    {
   1099        out << "// Structures from std140 blocks with padding removed\n";
   1100        out << "\n";
   1101        out << mappedStructs;
   1102        out << "\n";
   1103    }
   1104 
   1105    bool getDimensionsIgnoresBaseLevel = mCompileOptions.HLSLGetDimensionsIgnoresBaseLevel;
   1106    mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
   1107    mImageFunctionHLSL->imageFunctionHeader(out);
   1108    mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out);
   1109 
   1110    if (mUsesFragCoord)
   1111    {
   1112        out << "#define GL_USES_FRAG_COORD\n";
   1113    }
   1114 
   1115    if (mUsesPointCoord)
   1116    {
   1117        out << "#define GL_USES_POINT_COORD\n";
   1118    }
   1119 
   1120    if (mUsesFrontFacing)
   1121    {
   1122        out << "#define GL_USES_FRONT_FACING\n";
   1123    }
   1124 
   1125    if (mUsesHelperInvocation)
   1126    {
   1127        out << "#define GL_USES_HELPER_INVOCATION\n";
   1128    }
   1129 
   1130    if (mUsesPointSize)
   1131    {
   1132        out << "#define GL_USES_POINT_SIZE\n";
   1133    }
   1134 
   1135    if (mHasMultiviewExtensionEnabled)
   1136    {
   1137        out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
   1138    }
   1139 
   1140    if (mUsesVertexID)
   1141    {
   1142        out << "#define GL_USES_VERTEX_ID\n";
   1143    }
   1144 
   1145    if (mUsesViewID)
   1146    {
   1147        out << "#define GL_USES_VIEW_ID\n";
   1148    }
   1149 
   1150    if (mUsesFragDepth)
   1151    {
   1152        out << "#define GL_USES_FRAG_DEPTH\n";
   1153    }
   1154 
   1155    if (mUsesDepthRange)
   1156    {
   1157        out << "#define GL_USES_DEPTH_RANGE\n";
   1158    }
   1159 
   1160    if (mUsesXor)
   1161    {
   1162        out << "bool xor(bool p, bool q)\n"
   1163               "{\n"
   1164               "    return (p || q) && !(p && q);\n"
   1165               "}\n"
   1166               "\n";
   1167    }
   1168 
   1169    builtInFunctionEmulator->outputEmulatedFunctions(out);
   1170 }
   1171 
   1172 void OutputHLSL::visitSymbol(TIntermSymbol *node)
   1173 {
   1174    const TVariable &variable = node->variable();
   1175 
   1176    // Empty symbols can only appear in declarations and function arguments, and in either of those
   1177    // cases the symbol nodes are not visited.
   1178    ASSERT(variable.symbolType() != SymbolType::Empty);
   1179 
   1180    TInfoSinkBase &out = getInfoSink();
   1181 
   1182    // Handle accessing std140 structs by value
   1183    if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct &&
   1184        needStructMapping(node))
   1185    {
   1186        mNeedStructMapping = true;
   1187        out << "map";
   1188    }
   1189 
   1190    const ImmutableString &name     = variable.name();
   1191    const TSymbolUniqueId &uniqueId = variable.uniqueId();
   1192 
   1193    if (name == "gl_DepthRange")
   1194    {
   1195        mUsesDepthRange = true;
   1196        out << name;
   1197    }
   1198    else if (IsAtomicCounter(variable.getType().getBasicType()))
   1199    {
   1200        const TType &variableType = variable.getType();
   1201        if (variableType.getQualifier() == EvqUniform)
   1202        {
   1203            TLayoutQualifier layout             = variableType.getLayoutQualifier();
   1204            mReferencedUniforms[uniqueId.get()] = &variable;
   1205            out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset;
   1206        }
   1207        else
   1208        {
   1209            TString varName = DecorateVariableIfNeeded(variable);
   1210            out << varName << ", " << varName << "_offset";
   1211        }
   1212    }
   1213    else
   1214    {
   1215        const TType &variableType = variable.getType();
   1216        TQualifier qualifier      = variable.getType().getQualifier();
   1217 
   1218        ensureStructDefined(variableType);
   1219 
   1220        if (qualifier == EvqUniform)
   1221        {
   1222            const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
   1223 
   1224            if (interfaceBlock)
   1225            {
   1226                if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
   1227                {
   1228                    const TVariable *instanceVariable = nullptr;
   1229                    if (variableType.isInterfaceBlock())
   1230                    {
   1231                        instanceVariable = &variable;
   1232                    }
   1233                    mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
   1234                        new TReferencedBlock(interfaceBlock, instanceVariable);
   1235                }
   1236            }
   1237            else
   1238            {
   1239                mReferencedUniforms[uniqueId.get()] = &variable;
   1240            }
   1241 
   1242            out << DecorateVariableIfNeeded(variable);
   1243        }
   1244        else if (qualifier == EvqBuffer)
   1245        {
   1246            UNREACHABLE();
   1247        }
   1248        else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
   1249        {
   1250            mReferencedAttributes[uniqueId.get()] = &variable;
   1251            out << Decorate(name);
   1252        }
   1253        else if (IsVarying(qualifier))
   1254        {
   1255            mReferencedVaryings[uniqueId.get()] = &variable;
   1256            out << DecorateVariableIfNeeded(variable);
   1257            if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR")
   1258            {
   1259                mUsesViewID = true;
   1260            }
   1261        }
   1262        else if (qualifier == EvqFragmentOut)
   1263        {
   1264            mReferencedOutputVariables[uniqueId.get()] = &variable;
   1265            out << "out_" << name;
   1266        }
   1267        else if (qualifier == EvqFragColor)
   1268        {
   1269            out << "gl_Color[0]";
   1270            mUsesFragColor = true;
   1271        }
   1272        else if (qualifier == EvqFragData)
   1273        {
   1274            out << "gl_Color";
   1275            mUsesFragData = true;
   1276        }
   1277        else if (qualifier == EvqSecondaryFragColorEXT)
   1278        {
   1279            out << "gl_SecondaryColor[0]";
   1280            mUsesSecondaryColor = true;
   1281        }
   1282        else if (qualifier == EvqSecondaryFragDataEXT)
   1283        {
   1284            out << "gl_SecondaryColor";
   1285            mUsesSecondaryColor = true;
   1286        }
   1287        else if (qualifier == EvqFragCoord)
   1288        {
   1289            mUsesFragCoord = true;
   1290            out << name;
   1291        }
   1292        else if (qualifier == EvqPointCoord)
   1293        {
   1294            mUsesPointCoord = true;
   1295            out << name;
   1296        }
   1297        else if (qualifier == EvqFrontFacing)
   1298        {
   1299            mUsesFrontFacing = true;
   1300            out << name;
   1301        }
   1302        else if (qualifier == EvqHelperInvocation)
   1303        {
   1304            mUsesHelperInvocation = true;
   1305            out << name;
   1306        }
   1307        else if (qualifier == EvqPointSize)
   1308        {
   1309            mUsesPointSize = true;
   1310            out << name;
   1311        }
   1312        else if (qualifier == EvqInstanceID)
   1313        {
   1314            mUsesInstanceID = true;
   1315            out << name;
   1316        }
   1317        else if (qualifier == EvqVertexID)
   1318        {
   1319            mUsesVertexID = true;
   1320            out << name;
   1321        }
   1322        else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
   1323        {
   1324            mUsesFragDepth = true;
   1325            out << "gl_Depth";
   1326        }
   1327        else if (qualifier == EvqNumWorkGroups)
   1328        {
   1329            mUsesNumWorkGroups = true;
   1330            out << name;
   1331        }
   1332        else if (qualifier == EvqWorkGroupID)
   1333        {
   1334            mUsesWorkGroupID = true;
   1335            out << name;
   1336        }
   1337        else if (qualifier == EvqLocalInvocationID)
   1338        {
   1339            mUsesLocalInvocationID = true;
   1340            out << name;
   1341        }
   1342        else if (qualifier == EvqGlobalInvocationID)
   1343        {
   1344            mUsesGlobalInvocationID = true;
   1345            out << name;
   1346        }
   1347        else if (qualifier == EvqLocalInvocationIndex)
   1348        {
   1349            mUsesLocalInvocationIndex = true;
   1350            out << name;
   1351        }
   1352        else
   1353        {
   1354            out << DecorateVariableIfNeeded(variable);
   1355        }
   1356    }
   1357 }
   1358 
   1359 void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
   1360 {
   1361    if (type.isScalar() && !type.isArray())
   1362    {
   1363        if (op == EOpEqual)
   1364        {
   1365            outputTriplet(out, visit, "(", " == ", ")");
   1366        }
   1367        else
   1368        {
   1369            outputTriplet(out, visit, "(", " != ", ")");
   1370        }
   1371    }
   1372    else
   1373    {
   1374        if (visit == PreVisit && op == EOpNotEqual)
   1375        {
   1376            out << "!";
   1377        }
   1378 
   1379        if (type.isArray())
   1380        {
   1381            const TString &functionName = addArrayEqualityFunction(type);
   1382            outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
   1383        }
   1384        else if (type.getBasicType() == EbtStruct)
   1385        {
   1386            const TStructure &structure = *type.getStruct();
   1387            const TString &functionName = addStructEqualityFunction(structure);
   1388            outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
   1389        }
   1390        else
   1391        {
   1392            ASSERT(type.isMatrix() || type.isVector());
   1393            outputTriplet(out, visit, "all(", " == ", ")");
   1394        }
   1395    }
   1396 }
   1397 
   1398 void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
   1399 {
   1400    if (type.isArray())
   1401    {
   1402        const TString &functionName = addArrayAssignmentFunction(type);
   1403        outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
   1404    }
   1405    else
   1406    {
   1407        outputTriplet(out, visit, "(", " = ", ")");
   1408    }
   1409 }
   1410 
   1411 bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
   1412 {
   1413    for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
   1414    {
   1415        TIntermNode *ancestor               = getAncestorNode(n);
   1416        const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
   1417        if (ancestorBinary == nullptr)
   1418        {
   1419            return false;
   1420        }
   1421        switch (ancestorBinary->getOp())
   1422        {
   1423            case EOpIndexDirectStruct:
   1424            {
   1425                const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
   1426                const TIntermConstantUnion *index =
   1427                    ancestorBinary->getRight()->getAsConstantUnion();
   1428                const TField *field = structure->fields()[index->getIConst(0)];
   1429                if (IsSampler(field->type()->getBasicType()))
   1430                {
   1431                    return true;
   1432                }
   1433                break;
   1434            }
   1435            case EOpIndexDirect:
   1436                break;
   1437            default:
   1438                // Returning a sampler from indirect indexing is not supported.
   1439                return false;
   1440        }
   1441    }
   1442    return false;
   1443 }
   1444 
   1445 bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
   1446 {
   1447    TInfoSinkBase &out = getInfoSink();
   1448    if (visit == PostVisit)
   1449    {
   1450        out << ".";
   1451        node->writeOffsetsAsXYZW(&out);
   1452    }
   1453    return true;
   1454 }
   1455 
   1456 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
   1457 {
   1458    TInfoSinkBase &out = getInfoSink();
   1459 
   1460    switch (node->getOp())
   1461    {
   1462        case EOpComma:
   1463            outputTriplet(out, visit, "(", ", ", ")");
   1464            break;
   1465        case EOpAssign:
   1466            if (node->isArray())
   1467            {
   1468                TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
   1469                if (rightAgg != nullptr && rightAgg->isConstructor())
   1470                {
   1471                    const TString &functionName = addArrayConstructIntoFunction(node->getType());
   1472                    out << functionName << "(";
   1473                    node->getLeft()->traverse(this);
   1474                    TIntermSequence *seq = rightAgg->getSequence();
   1475                    for (auto &arrayElement : *seq)
   1476                    {
   1477                        out << ", ";
   1478                        arrayElement->traverse(this);
   1479                    }
   1480                    out << ")";
   1481                    return false;
   1482                }
   1483                // ArrayReturnValueToOutParameter should have eliminated expressions where a
   1484                // function call is assigned.
   1485                ASSERT(rightAgg == nullptr);
   1486            }
   1487            // Assignment expressions with atomic functions should be transformed into atomic
   1488            // function calls in HLSL.
   1489            // e.g. original_value = atomicAdd(dest, value) should be translated into
   1490            //      InterlockedAdd(dest, value, original_value);
   1491            else if (IsAtomicFunctionForSharedVariableDirectAssign(*node))
   1492            {
   1493                TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate();
   1494                TOperator atomicFunctionOp           = atomicFunctionNode->getOp();
   1495                out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp);
   1496                TIntermSequence *argumentSeq = atomicFunctionNode->getSequence();
   1497                ASSERT(argumentSeq->size() >= 2u);
   1498                for (auto &argument : *argumentSeq)
   1499                {
   1500                    argument->traverse(this);
   1501                    out << ", ";
   1502                }
   1503                node->getLeft()->traverse(this);
   1504                out << ")";
   1505                return false;
   1506            }
   1507            else if (IsInShaderStorageBlock(node->getLeft()))
   1508            {
   1509                mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft());
   1510                out << ", ";
   1511                if (IsInShaderStorageBlock(node->getRight()))
   1512                {
   1513                    mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
   1514                }
   1515                else
   1516                {
   1517                    node->getRight()->traverse(this);
   1518                }
   1519 
   1520                out << ")";
   1521                return false;
   1522            }
   1523            else if (IsInShaderStorageBlock(node->getRight()))
   1524            {
   1525                node->getLeft()->traverse(this);
   1526                out << " = ";
   1527                mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
   1528                return false;
   1529            }
   1530 
   1531            outputAssign(visit, node->getType(), out);
   1532            break;
   1533        case EOpInitialize:
   1534            if (visit == PreVisit)
   1535            {
   1536                TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
   1537                ASSERT(symbolNode);
   1538                TIntermTyped *initializer = node->getRight();
   1539 
   1540                // Global initializers must be constant at this point.
   1541                ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue());
   1542 
   1543                // GLSL allows to write things like "float x = x;" where a new variable x is defined
   1544                // and the value of an existing variable x is assigned. HLSL uses C semantics (the
   1545                // new variable is created before the assignment is evaluated), so we need to
   1546                // convert
   1547                // this to "float t = x, x = t;".
   1548                if (writeSameSymbolInitializer(out, symbolNode, initializer))
   1549                {
   1550                    // Skip initializing the rest of the expression
   1551                    return false;
   1552                }
   1553                else if (writeConstantInitialization(out, symbolNode, initializer))
   1554                {
   1555                    return false;
   1556                }
   1557            }
   1558            else if (visit == InVisit)
   1559            {
   1560                out << " = ";
   1561                if (IsInShaderStorageBlock(node->getRight()))
   1562                {
   1563                    mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight());
   1564                    return false;
   1565                }
   1566            }
   1567            break;
   1568        case EOpAddAssign:
   1569            outputTriplet(out, visit, "(", " += ", ")");
   1570            break;
   1571        case EOpSubAssign:
   1572            outputTriplet(out, visit, "(", " -= ", ")");
   1573            break;
   1574        case EOpMulAssign:
   1575            outputTriplet(out, visit, "(", " *= ", ")");
   1576            break;
   1577        case EOpVectorTimesScalarAssign:
   1578            outputTriplet(out, visit, "(", " *= ", ")");
   1579            break;
   1580        case EOpMatrixTimesScalarAssign:
   1581            outputTriplet(out, visit, "(", " *= ", ")");
   1582            break;
   1583        case EOpVectorTimesMatrixAssign:
   1584            if (visit == PreVisit)
   1585            {
   1586                out << "(";
   1587            }
   1588            else if (visit == InVisit)
   1589            {
   1590                out << " = mul(";
   1591                node->getLeft()->traverse(this);
   1592                out << ", transpose(";
   1593            }
   1594            else
   1595            {
   1596                out << ")))";
   1597            }
   1598            break;
   1599        case EOpMatrixTimesMatrixAssign:
   1600            if (visit == PreVisit)
   1601            {
   1602                out << "(";
   1603            }
   1604            else if (visit == InVisit)
   1605            {
   1606                out << " = transpose(mul(transpose(";
   1607                node->getLeft()->traverse(this);
   1608                out << "), transpose(";
   1609            }
   1610            else
   1611            {
   1612                out << "))))";
   1613            }
   1614            break;
   1615        case EOpDivAssign:
   1616            outputTriplet(out, visit, "(", " /= ", ")");
   1617            break;
   1618        case EOpIModAssign:
   1619            outputTriplet(out, visit, "(", " %= ", ")");
   1620            break;
   1621        case EOpBitShiftLeftAssign:
   1622            outputTriplet(out, visit, "(", " <<= ", ")");
   1623            break;
   1624        case EOpBitShiftRightAssign:
   1625            outputTriplet(out, visit, "(", " >>= ", ")");
   1626            break;
   1627        case EOpBitwiseAndAssign:
   1628            outputTriplet(out, visit, "(", " &= ", ")");
   1629            break;
   1630        case EOpBitwiseXorAssign:
   1631            outputTriplet(out, visit, "(", " ^= ", ")");
   1632            break;
   1633        case EOpBitwiseOrAssign:
   1634            outputTriplet(out, visit, "(", " |= ", ")");
   1635            break;
   1636        case EOpIndexDirect:
   1637        {
   1638            const TType &leftType = node->getLeft()->getType();
   1639            if (leftType.isInterfaceBlock())
   1640            {
   1641                if (visit == PreVisit)
   1642                {
   1643                    TIntermSymbol *instanceArraySymbol    = node->getLeft()->getAsSymbolNode();
   1644                    const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
   1645 
   1646                    ASSERT(leftType.getQualifier() == EvqUniform);
   1647                    if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
   1648                    {
   1649                        mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
   1650                            new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable());
   1651                    }
   1652                    const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
   1653                    out << mResourcesHLSL->InterfaceBlockInstanceString(
   1654                        instanceArraySymbol->getName(), arrayIndex);
   1655                    return false;
   1656                }
   1657            }
   1658            else if (ancestorEvaluatesToSamplerInStruct())
   1659            {
   1660                // All parts of an expression that access a sampler in a struct need to use _ as
   1661                // separator to access the sampler variable that has been moved out of the struct.
   1662                outputTriplet(out, visit, "", "_", "");
   1663            }
   1664            else if (IsAtomicCounter(leftType.getBasicType()))
   1665            {
   1666                outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
   1667            }
   1668            else
   1669            {
   1670                outputTriplet(out, visit, "", "[", "]");
   1671                if (visit == PostVisit)
   1672                {
   1673                    const TInterfaceBlock *interfaceBlock =
   1674                        GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
   1675                    if (interfaceBlock &&
   1676                        mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
   1677                    {
   1678                        // If the uniform block member's type is not structure, we had explicitly
   1679                        // packed the member into a structure, so need to add an operator of field
   1680                        // slection.
   1681                        const TField *field    = interfaceBlock->fields()[0];
   1682                        const TType *fieldType = field->type();
   1683                        if (fieldType->isMatrix() || fieldType->isVectorArray() ||
   1684                            fieldType->isScalarArray())
   1685                        {
   1686                            out << "." << Decorate(field->name());
   1687                        }
   1688                    }
   1689                }
   1690            }
   1691        }
   1692        break;
   1693        case EOpIndexIndirect:
   1694        {
   1695            // We do not currently support indirect references to interface blocks
   1696            ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
   1697 
   1698            const TType &leftType = node->getLeft()->getType();
   1699            if (IsAtomicCounter(leftType.getBasicType()))
   1700            {
   1701                outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE");
   1702            }
   1703            else
   1704            {
   1705                outputTriplet(out, visit, "", "[", "]");
   1706                if (visit == PostVisit)
   1707                {
   1708                    const TInterfaceBlock *interfaceBlock =
   1709                        GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
   1710                    if (interfaceBlock &&
   1711                        mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
   1712                    {
   1713                        // If the uniform block member's type is not structure, we had explicitly
   1714                        // packed the member into a structure, so need to add an operator of field
   1715                        // slection.
   1716                        const TField *field    = interfaceBlock->fields()[0];
   1717                        const TType *fieldType = field->type();
   1718                        if (fieldType->isMatrix() || fieldType->isVectorArray() ||
   1719                            fieldType->isScalarArray())
   1720                        {
   1721                            out << "." << Decorate(field->name());
   1722                        }
   1723                    }
   1724                }
   1725            }
   1726            break;
   1727        }
   1728        case EOpIndexDirectStruct:
   1729        {
   1730            const TStructure *structure       = node->getLeft()->getType().getStruct();
   1731            const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
   1732            const TField *field               = structure->fields()[index->getIConst(0)];
   1733 
   1734            // In cases where indexing returns a sampler, we need to access the sampler variable
   1735            // that has been moved out of the struct.
   1736            bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
   1737            if (visit == PreVisit && indexingReturnsSampler)
   1738            {
   1739                // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
   1740                // This prefix is only output at the beginning of the indexing expression, which
   1741                // may have multiple parts.
   1742                out << "angle";
   1743            }
   1744            if (!indexingReturnsSampler)
   1745            {
   1746                // All parts of an expression that access a sampler in a struct need to use _ as
   1747                // separator to access the sampler variable that has been moved out of the struct.
   1748                indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct();
   1749            }
   1750            if (visit == InVisit)
   1751            {
   1752                if (indexingReturnsSampler)
   1753                {
   1754                    out << "_" << field->name();
   1755                }
   1756                else
   1757                {
   1758                    out << "." << DecorateField(field->name(), *structure);
   1759                }
   1760 
   1761                return false;
   1762            }
   1763        }
   1764        break;
   1765        case EOpIndexDirectInterfaceBlock:
   1766        {
   1767            ASSERT(!IsInShaderStorageBlock(node->getLeft()));
   1768            bool structInStd140UniformBlock = node->getBasicType() == EbtStruct &&
   1769                                              IsInStd140UniformBlock(node->getLeft()) &&
   1770                                              needStructMapping(node);
   1771            if (visit == PreVisit && structInStd140UniformBlock)
   1772            {
   1773                mNeedStructMapping = true;
   1774                out << "map";
   1775            }
   1776            if (visit == InVisit)
   1777            {
   1778                const TInterfaceBlock *interfaceBlock =
   1779                    node->getLeft()->getType().getInterfaceBlock();
   1780                const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
   1781                const TField *field               = interfaceBlock->fields()[index->getIConst(0)];
   1782                if (structInStd140UniformBlock ||
   1783                    mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
   1784                {
   1785                    out << "_";
   1786                }
   1787                else
   1788                {
   1789                    out << ".";
   1790                }
   1791                out << Decorate(field->name());
   1792 
   1793                return false;
   1794            }
   1795            break;
   1796        }
   1797        case EOpAdd:
   1798            outputTriplet(out, visit, "(", " + ", ")");
   1799            break;
   1800        case EOpSub:
   1801            outputTriplet(out, visit, "(", " - ", ")");
   1802            break;
   1803        case EOpMul:
   1804            outputTriplet(out, visit, "(", " * ", ")");
   1805            break;
   1806        case EOpDiv:
   1807            outputTriplet(out, visit, "(", " / ", ")");
   1808            break;
   1809        case EOpIMod:
   1810            outputTriplet(out, visit, "(", " % ", ")");
   1811            break;
   1812        case EOpBitShiftLeft:
   1813            outputTriplet(out, visit, "(", " << ", ")");
   1814            break;
   1815        case EOpBitShiftRight:
   1816            outputTriplet(out, visit, "(", " >> ", ")");
   1817            break;
   1818        case EOpBitwiseAnd:
   1819            outputTriplet(out, visit, "(", " & ", ")");
   1820            break;
   1821        case EOpBitwiseXor:
   1822            outputTriplet(out, visit, "(", " ^ ", ")");
   1823            break;
   1824        case EOpBitwiseOr:
   1825            outputTriplet(out, visit, "(", " | ", ")");
   1826            break;
   1827        case EOpEqual:
   1828        case EOpNotEqual:
   1829            outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
   1830            break;
   1831        case EOpLessThan:
   1832            outputTriplet(out, visit, "(", " < ", ")");
   1833            break;
   1834        case EOpGreaterThan:
   1835            outputTriplet(out, visit, "(", " > ", ")");
   1836            break;
   1837        case EOpLessThanEqual:
   1838            outputTriplet(out, visit, "(", " <= ", ")");
   1839            break;
   1840        case EOpGreaterThanEqual:
   1841            outputTriplet(out, visit, "(", " >= ", ")");
   1842            break;
   1843        case EOpVectorTimesScalar:
   1844            outputTriplet(out, visit, "(", " * ", ")");
   1845            break;
   1846        case EOpMatrixTimesScalar:
   1847            outputTriplet(out, visit, "(", " * ", ")");
   1848            break;
   1849        case EOpVectorTimesMatrix:
   1850            outputTriplet(out, visit, "mul(", ", transpose(", "))");
   1851            break;
   1852        case EOpMatrixTimesVector:
   1853            outputTriplet(out, visit, "mul(transpose(", "), ", ")");
   1854            break;
   1855        case EOpMatrixTimesMatrix:
   1856            outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
   1857            break;
   1858        case EOpLogicalOr:
   1859            // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have
   1860            // been unfolded.
   1861            ASSERT(!node->getRight()->hasSideEffects());
   1862            outputTriplet(out, visit, "(", " || ", ")");
   1863            return true;
   1864        case EOpLogicalXor:
   1865            mUsesXor = true;
   1866            outputTriplet(out, visit, "xor(", ", ", ")");
   1867            break;
   1868        case EOpLogicalAnd:
   1869            // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have
   1870            // been unfolded.
   1871            ASSERT(!node->getRight()->hasSideEffects());
   1872            outputTriplet(out, visit, "(", " && ", ")");
   1873            return true;
   1874        default:
   1875            UNREACHABLE();
   1876    }
   1877 
   1878    return true;
   1879 }
   1880 
   1881 bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
   1882 {
   1883    TInfoSinkBase &out = getInfoSink();
   1884 
   1885    switch (node->getOp())
   1886    {
   1887        case EOpNegative:
   1888            outputTriplet(out, visit, "(-", "", ")");
   1889            break;
   1890        case EOpPositive:
   1891            outputTriplet(out, visit, "(+", "", ")");
   1892            break;
   1893        case EOpLogicalNot:
   1894            outputTriplet(out, visit, "(!", "", ")");
   1895            break;
   1896        case EOpBitwiseNot:
   1897            outputTriplet(out, visit, "(~", "", ")");
   1898            break;
   1899        case EOpPostIncrement:
   1900            outputTriplet(out, visit, "(", "", "++)");
   1901            break;
   1902        case EOpPostDecrement:
   1903            outputTriplet(out, visit, "(", "", "--)");
   1904            break;
   1905        case EOpPreIncrement:
   1906            outputTriplet(out, visit, "(++", "", ")");
   1907            break;
   1908        case EOpPreDecrement:
   1909            outputTriplet(out, visit, "(--", "", ")");
   1910            break;
   1911        case EOpRadians:
   1912            outputTriplet(out, visit, "radians(", "", ")");
   1913            break;
   1914        case EOpDegrees:
   1915            outputTriplet(out, visit, "degrees(", "", ")");
   1916            break;
   1917        case EOpSin:
   1918            outputTriplet(out, visit, "sin(", "", ")");
   1919            break;
   1920        case EOpCos:
   1921            outputTriplet(out, visit, "cos(", "", ")");
   1922            break;
   1923        case EOpTan:
   1924            outputTriplet(out, visit, "tan(", "", ")");
   1925            break;
   1926        case EOpAsin:
   1927            outputTriplet(out, visit, "asin(", "", ")");
   1928            break;
   1929        case EOpAcos:
   1930            outputTriplet(out, visit, "acos(", "", ")");
   1931            break;
   1932        case EOpAtan:
   1933            outputTriplet(out, visit, "atan(", "", ")");
   1934            break;
   1935        case EOpSinh:
   1936            outputTriplet(out, visit, "sinh(", "", ")");
   1937            break;
   1938        case EOpCosh:
   1939            outputTriplet(out, visit, "cosh(", "", ")");
   1940            break;
   1941        case EOpTanh:
   1942        case EOpAsinh:
   1943        case EOpAcosh:
   1944        case EOpAtanh:
   1945            ASSERT(node->getUseEmulatedFunction());
   1946            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   1947            break;
   1948        case EOpExp:
   1949            outputTriplet(out, visit, "exp(", "", ")");
   1950            break;
   1951        case EOpLog:
   1952            outputTriplet(out, visit, "log(", "", ")");
   1953            break;
   1954        case EOpExp2:
   1955            outputTriplet(out, visit, "exp2(", "", ")");
   1956            break;
   1957        case EOpLog2:
   1958            outputTriplet(out, visit, "log2(", "", ")");
   1959            break;
   1960        case EOpSqrt:
   1961            outputTriplet(out, visit, "sqrt(", "", ")");
   1962            break;
   1963        case EOpInversesqrt:
   1964            outputTriplet(out, visit, "rsqrt(", "", ")");
   1965            break;
   1966        case EOpAbs:
   1967            outputTriplet(out, visit, "abs(", "", ")");
   1968            break;
   1969        case EOpSign:
   1970            outputTriplet(out, visit, "sign(", "", ")");
   1971            break;
   1972        case EOpFloor:
   1973            outputTriplet(out, visit, "floor(", "", ")");
   1974            break;
   1975        case EOpTrunc:
   1976            outputTriplet(out, visit, "trunc(", "", ")");
   1977            break;
   1978        case EOpRound:
   1979            outputTriplet(out, visit, "round(", "", ")");
   1980            break;
   1981        case EOpRoundEven:
   1982            ASSERT(node->getUseEmulatedFunction());
   1983            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   1984            break;
   1985        case EOpCeil:
   1986            outputTriplet(out, visit, "ceil(", "", ")");
   1987            break;
   1988        case EOpFract:
   1989            outputTriplet(out, visit, "frac(", "", ")");
   1990            break;
   1991        case EOpIsnan:
   1992            if (node->getUseEmulatedFunction())
   1993                writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   1994            else
   1995                outputTriplet(out, visit, "isnan(", "", ")");
   1996            mRequiresIEEEStrictCompiling = true;
   1997            break;
   1998        case EOpIsinf:
   1999            outputTriplet(out, visit, "isinf(", "", ")");
   2000            break;
   2001        case EOpFloatBitsToInt:
   2002            outputTriplet(out, visit, "asint(", "", ")");
   2003            break;
   2004        case EOpFloatBitsToUint:
   2005            outputTriplet(out, visit, "asuint(", "", ")");
   2006            break;
   2007        case EOpIntBitsToFloat:
   2008            outputTriplet(out, visit, "asfloat(", "", ")");
   2009            break;
   2010        case EOpUintBitsToFloat:
   2011            outputTriplet(out, visit, "asfloat(", "", ")");
   2012            break;
   2013        case EOpPackSnorm2x16:
   2014        case EOpPackUnorm2x16:
   2015        case EOpPackHalf2x16:
   2016        case EOpUnpackSnorm2x16:
   2017        case EOpUnpackUnorm2x16:
   2018        case EOpUnpackHalf2x16:
   2019        case EOpPackUnorm4x8:
   2020        case EOpPackSnorm4x8:
   2021        case EOpUnpackUnorm4x8:
   2022        case EOpUnpackSnorm4x8:
   2023            ASSERT(node->getUseEmulatedFunction());
   2024            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2025            break;
   2026        case EOpLength:
   2027            outputTriplet(out, visit, "length(", "", ")");
   2028            break;
   2029        case EOpNormalize:
   2030            outputTriplet(out, visit, "normalize(", "", ")");
   2031            break;
   2032        case EOpTranspose:
   2033            outputTriplet(out, visit, "transpose(", "", ")");
   2034            break;
   2035        case EOpDeterminant:
   2036            outputTriplet(out, visit, "determinant(transpose(", "", "))");
   2037            break;
   2038        case EOpInverse:
   2039            ASSERT(node->getUseEmulatedFunction());
   2040            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2041            break;
   2042 
   2043        case EOpAny:
   2044            outputTriplet(out, visit, "any(", "", ")");
   2045            break;
   2046        case EOpAll:
   2047            outputTriplet(out, visit, "all(", "", ")");
   2048            break;
   2049        case EOpNotComponentWise:
   2050            outputTriplet(out, visit, "(!", "", ")");
   2051            break;
   2052        case EOpBitfieldReverse:
   2053            outputTriplet(out, visit, "reversebits(", "", ")");
   2054            break;
   2055        case EOpBitCount:
   2056            outputTriplet(out, visit, "countbits(", "", ")");
   2057            break;
   2058        case EOpFindLSB:
   2059            // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested
   2060            // in GLSLTest and results are consistent with GL.
   2061            outputTriplet(out, visit, "firstbitlow(", "", ")");
   2062            break;
   2063        case EOpFindMSB:
   2064            // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is
   2065            // tested in GLSLTest and results are consistent with GL.
   2066            outputTriplet(out, visit, "firstbithigh(", "", ")");
   2067            break;
   2068        case EOpArrayLength:
   2069        {
   2070            TIntermTyped *operand = node->getOperand();
   2071            ASSERT(IsInShaderStorageBlock(operand));
   2072            mSSBOOutputHLSL->outputLengthFunctionCall(operand);
   2073            return false;
   2074        }
   2075        default:
   2076            UNREACHABLE();
   2077    }
   2078 
   2079    return true;
   2080 }
   2081 
   2082 ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
   2083 {
   2084    if (node->getAsSymbolNode())
   2085    {
   2086        ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty);
   2087        return node->getAsSymbolNode()->getName();
   2088    }
   2089    TIntermBinary *nodeBinary = node->getAsBinaryNode();
   2090    switch (nodeBinary->getOp())
   2091    {
   2092        case EOpIndexDirect:
   2093        {
   2094            int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
   2095 
   2096            std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
   2097            prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
   2098            return ImmutableString(prefixSink.str());
   2099        }
   2100        case EOpIndexDirectStruct:
   2101        {
   2102            const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
   2103            int index           = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
   2104            const TField *field = s->fields()[index];
   2105 
   2106            std::stringstream prefixSink = sh::InitializeStream<std::stringstream>();
   2107            prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
   2108                       << field->name();
   2109            return ImmutableString(prefixSink.str());
   2110        }
   2111        default:
   2112            UNREACHABLE();
   2113            return kEmptyImmutableString;
   2114    }
   2115 }
   2116 
   2117 bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
   2118 {
   2119    TInfoSinkBase &out = getInfoSink();
   2120 
   2121    bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition();
   2122 
   2123    if (mInsideFunction)
   2124    {
   2125        outputLineDirective(out, node->getLine().first_line);
   2126        out << "{\n";
   2127        if (isMainBlock)
   2128        {
   2129            if (mShaderType == GL_COMPUTE_SHADER)
   2130            {
   2131                out << "initGLBuiltins(input);\n";
   2132            }
   2133            else
   2134            {
   2135                out << "@@ MAIN PROLOGUE @@\n";
   2136            }
   2137        }
   2138    }
   2139 
   2140    for (TIntermNode *statement : *node->getSequence())
   2141    {
   2142        outputLineDirective(out, statement->getLine().first_line);
   2143 
   2144        statement->traverse(this);
   2145 
   2146        // Don't output ; after case labels, they're terminated by :
   2147        // This is needed especially since outputting a ; after a case statement would turn empty
   2148        // case statements into non-empty case statements, disallowing fall-through from them.
   2149        // Also the output code is clearer if we don't output ; after statements where it is not
   2150        // needed:
   2151        //  * if statements
   2152        //  * switch statements
   2153        //  * blocks
   2154        //  * function definitions
   2155        //  * loops (do-while loops output the semicolon in VisitLoop)
   2156        //  * declarations that don't generate output.
   2157        if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr &&
   2158            statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr &&
   2159            statement->getAsSwitchNode() == nullptr &&
   2160            statement->getAsFunctionDefinition() == nullptr &&
   2161            (statement->getAsDeclarationNode() == nullptr ||
   2162             IsDeclarationWrittenOut(statement->getAsDeclarationNode())) &&
   2163            statement->getAsGlobalQualifierDeclarationNode() == nullptr)
   2164        {
   2165            out << ";\n";
   2166        }
   2167    }
   2168 
   2169    if (mInsideFunction)
   2170    {
   2171        outputLineDirective(out, node->getLine().last_line);
   2172        if (isMainBlock && shaderNeedsGenerateOutput())
   2173        {
   2174            // We could have an empty main, a main function without a branch at the end, or a main
   2175            // function with a discard statement at the end. In these cases we need to add a return
   2176            // statement.
   2177            bool needReturnStatement =
   2178                node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() ||
   2179                node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn;
   2180            if (needReturnStatement)
   2181            {
   2182                out << "return " << generateOutputCall() << ";\n";
   2183            }
   2184        }
   2185        out << "}\n";
   2186    }
   2187 
   2188    return false;
   2189 }
   2190 
   2191 bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
   2192 {
   2193    TInfoSinkBase &out = getInfoSink();
   2194 
   2195    ASSERT(mCurrentFunctionMetadata == nullptr);
   2196 
   2197    size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
   2198    ASSERT(index != CallDAG::InvalidIndex);
   2199    mCurrentFunctionMetadata = &mASTMetadataList[index];
   2200 
   2201    const TFunction *func = node->getFunction();
   2202 
   2203    if (func->isMain())
   2204    {
   2205        // The stub strings below are replaced when shader is dynamically defined by its layout:
   2206        switch (mShaderType)
   2207        {
   2208            case GL_VERTEX_SHADER:
   2209                out << "@@ VERTEX ATTRIBUTES @@\n\n"
   2210                    << "@@ VERTEX OUTPUT @@\n\n"
   2211                    << "VS_OUTPUT main(VS_INPUT input)";
   2212                break;
   2213            case GL_FRAGMENT_SHADER:
   2214                out << "@@ PIXEL OUTPUT @@\n\n";
   2215                if (mIsEarlyFragmentTestsSpecified)
   2216                {
   2217                    out << "[earlydepthstencil]\n";
   2218                }
   2219                out << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)";
   2220                break;
   2221            case GL_COMPUTE_SHADER:
   2222                out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", "
   2223                    << mWorkGroupSize[2] << ")]\n";
   2224                out << "void main(CS_INPUT input)";
   2225                break;
   2226            default:
   2227                UNREACHABLE();
   2228                break;
   2229        }
   2230    }
   2231    else
   2232    {
   2233        out << TypeString(node->getFunctionPrototype()->getType()) << " ";
   2234        out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func)
   2235            << (mOutputLod0Function ? "Lod0(" : "(");
   2236 
   2237        size_t paramCount = func->getParamCount();
   2238        for (unsigned int i = 0; i < paramCount; i++)
   2239        {
   2240            const TVariable *param = func->getParam(i);
   2241            ensureStructDefined(param->getType());
   2242 
   2243            writeParameter(param, out);
   2244 
   2245            if (i < paramCount - 1)
   2246            {
   2247                out << ", ";
   2248            }
   2249        }
   2250 
   2251        out << ")\n";
   2252    }
   2253 
   2254    mInsideFunction = true;
   2255    if (func->isMain())
   2256    {
   2257        mInsideMain = true;
   2258    }
   2259    // The function body node will output braces.
   2260    node->getBody()->traverse(this);
   2261    mInsideFunction = false;
   2262    mInsideMain     = false;
   2263 
   2264    mCurrentFunctionMetadata = nullptr;
   2265 
   2266    bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
   2267    if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
   2268    {
   2269        ASSERT(!node->getFunction()->isMain());
   2270        mOutputLod0Function = true;
   2271        node->traverse(this);
   2272        mOutputLod0Function = false;
   2273    }
   2274 
   2275    return false;
   2276 }
   2277 
   2278 bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
   2279 {
   2280    if (visit == PreVisit)
   2281    {
   2282        TIntermSequence *sequence = node->getSequence();
   2283        TIntermTyped *declarator  = (*sequence)[0]->getAsTyped();
   2284        ASSERT(sequence->size() == 1);
   2285        ASSERT(declarator);
   2286 
   2287        if (IsDeclarationWrittenOut(node))
   2288        {
   2289            TInfoSinkBase &out = getInfoSink();
   2290            ensureStructDefined(declarator->getType());
   2291 
   2292            if (!declarator->getAsSymbolNode() ||
   2293                declarator->getAsSymbolNode()->variable().symbolType() !=
   2294                    SymbolType::Empty)  // Variable declaration
   2295            {
   2296                if (declarator->getQualifier() == EvqShared)
   2297                {
   2298                    out << "groupshared ";
   2299                }
   2300                else if (!mInsideFunction)
   2301                {
   2302                    out << "static ";
   2303                }
   2304 
   2305                out << TypeString(declarator->getType()) + " ";
   2306 
   2307                TIntermSymbol *symbol = declarator->getAsSymbolNode();
   2308 
   2309                if (symbol)
   2310                {
   2311                    symbol->traverse(this);
   2312                    out << ArrayString(symbol->getType());
   2313                    // Temporarily disable shadred memory initialization. It is very slow for D3D11
   2314                    // drivers to compile a compute shader if we add code to initialize a
   2315                    // groupshared array variable with a large array size. And maybe produce
   2316                    // incorrect result. See http://anglebug.com/3226.
   2317                    if (declarator->getQualifier() != EvqShared)
   2318                    {
   2319                        out << " = " + zeroInitializer(symbol->getType());
   2320                    }
   2321                }
   2322                else
   2323                {
   2324                    declarator->traverse(this);
   2325                }
   2326            }
   2327        }
   2328        else if (IsVaryingOut(declarator->getQualifier()))
   2329        {
   2330            TIntermSymbol *symbol = declarator->getAsSymbolNode();
   2331            ASSERT(symbol);  // Varying declarations can't have initializers.
   2332 
   2333            const TVariable &variable = symbol->variable();
   2334 
   2335            if (variable.symbolType() != SymbolType::Empty)
   2336            {
   2337                // Vertex outputs which are declared but not written to should still be declared to
   2338                // allow successful linking.
   2339                mReferencedVaryings[symbol->uniqueId().get()] = &variable;
   2340            }
   2341        }
   2342    }
   2343    return false;
   2344 }
   2345 
   2346 bool OutputHLSL::visitGlobalQualifierDeclaration(Visit visit,
   2347                                                 TIntermGlobalQualifierDeclaration *node)
   2348 {
   2349    // Do not do any translation
   2350    return false;
   2351 }
   2352 
   2353 void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
   2354 {
   2355    TInfoSinkBase &out = getInfoSink();
   2356 
   2357    size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
   2358    // Skip the prototype if it is not implemented (and thus not used)
   2359    if (index == CallDAG::InvalidIndex)
   2360    {
   2361        return;
   2362    }
   2363 
   2364    const TFunction *func = node->getFunction();
   2365 
   2366    TString name = DecorateFunctionIfNeeded(func);
   2367    out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func)
   2368        << (mOutputLod0Function ? "Lod0(" : "(");
   2369 
   2370    size_t paramCount = func->getParamCount();
   2371    for (unsigned int i = 0; i < paramCount; i++)
   2372    {
   2373        writeParameter(func->getParam(i), out);
   2374 
   2375        if (i < paramCount - 1)
   2376        {
   2377            out << ", ";
   2378        }
   2379    }
   2380 
   2381    out << ");\n";
   2382 
   2383    // Also prototype the Lod0 variant if needed
   2384    bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
   2385    if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
   2386    {
   2387        mOutputLod0Function = true;
   2388        node->traverse(this);
   2389        mOutputLod0Function = false;
   2390    }
   2391 }
   2392 
   2393 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
   2394 {
   2395    TInfoSinkBase &out = getInfoSink();
   2396 
   2397    switch (node->getOp())
   2398    {
   2399        case EOpCallFunctionInAST:
   2400        case EOpCallInternalRawFunction:
   2401        default:
   2402        {
   2403            TIntermSequence *arguments = node->getSequence();
   2404 
   2405            bool lod0 = (mInsideDiscontinuousLoop || mOutputLod0Function) &&
   2406                        mShaderType == GL_FRAGMENT_SHADER;
   2407 
   2408            // No raw function is expected.
   2409            ASSERT(node->getOp() != EOpCallInternalRawFunction);
   2410 
   2411            if (node->getOp() == EOpCallFunctionInAST)
   2412            {
   2413                if (node->isArray())
   2414                {
   2415                    UNIMPLEMENTED();
   2416                }
   2417                size_t index = mCallDag.findIndex(node->getFunction()->uniqueId());
   2418                ASSERT(index != CallDAG::InvalidIndex);
   2419                lod0 &= mASTMetadataList[index].mNeedsLod0;
   2420 
   2421                out << DecorateFunctionIfNeeded(node->getFunction());
   2422                out << DisambiguateFunctionName(node->getSequence());
   2423                out << (lod0 ? "Lod0(" : "(");
   2424            }
   2425            else if (node->getFunction()->isImageFunction())
   2426            {
   2427                const ImmutableString &name              = node->getFunction()->name();
   2428                TType type                               = (*arguments)[0]->getAsTyped()->getType();
   2429                const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction(
   2430                    name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat,
   2431                    type.getMemoryQualifier().readonly);
   2432                out << imageFunctionName << "(";
   2433            }
   2434            else if (node->getFunction()->isAtomicCounterFunction())
   2435            {
   2436                const ImmutableString &name = node->getFunction()->name();
   2437                ImmutableString atomicFunctionName =
   2438                    mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name);
   2439                out << atomicFunctionName << "(";
   2440            }
   2441            else
   2442            {
   2443                const ImmutableString &name = node->getFunction()->name();
   2444                TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
   2445                int coords = 0;  // textureSize(gsampler2DMS) doesn't have a second argument.
   2446                if (arguments->size() > 1)
   2447                {
   2448                    coords = (*arguments)[1]->getAsTyped()->getNominalSize();
   2449                }
   2450                const ImmutableString &textureFunctionName =
   2451                    mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords,
   2452                                                             arguments->size(), lod0, mShaderType);
   2453                out << textureFunctionName << "(";
   2454            }
   2455 
   2456            for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
   2457            {
   2458                TIntermTyped *typedArg = (*arg)->getAsTyped();
   2459                if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
   2460                {
   2461                    out << "texture_";
   2462                    (*arg)->traverse(this);
   2463                    out << ", sampler_";
   2464                }
   2465 
   2466                (*arg)->traverse(this);
   2467 
   2468                if (typedArg->getType().isStructureContainingSamplers())
   2469                {
   2470                    const TType &argType = typedArg->getType();
   2471                    TVector<const TVariable *> samplerSymbols;
   2472                    ImmutableString structName = samplerNamePrefixFromStruct(typedArg);
   2473                    std::string namePrefix     = "angle_";
   2474                    namePrefix += structName.data();
   2475                    argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols,
   2476                                                 nullptr, mSymbolTable);
   2477                    for (const TVariable *sampler : samplerSymbols)
   2478                    {
   2479                        if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
   2480                        {
   2481                            out << ", texture_" << sampler->name();
   2482                            out << ", sampler_" << sampler->name();
   2483                        }
   2484                        else
   2485                        {
   2486                            // In case of HLSL 4.1+, this symbol is the sampler index, and in case
   2487                            // of D3D9, it's the sampler variable.
   2488                            out << ", " << sampler->name();
   2489                        }
   2490                    }
   2491                }
   2492 
   2493                if (arg < arguments->end() - 1)
   2494                {
   2495                    out << ", ";
   2496                }
   2497            }
   2498 
   2499            out << ")";
   2500 
   2501            return false;
   2502        }
   2503        case EOpConstruct:
   2504            outputConstructor(out, visit, node);
   2505            break;
   2506        case EOpEqualComponentWise:
   2507            outputTriplet(out, visit, "(", " == ", ")");
   2508            break;
   2509        case EOpNotEqualComponentWise:
   2510            outputTriplet(out, visit, "(", " != ", ")");
   2511            break;
   2512        case EOpLessThanComponentWise:
   2513            outputTriplet(out, visit, "(", " < ", ")");
   2514            break;
   2515        case EOpGreaterThanComponentWise:
   2516            outputTriplet(out, visit, "(", " > ", ")");
   2517            break;
   2518        case EOpLessThanEqualComponentWise:
   2519            outputTriplet(out, visit, "(", " <= ", ")");
   2520            break;
   2521        case EOpGreaterThanEqualComponentWise:
   2522            outputTriplet(out, visit, "(", " >= ", ")");
   2523            break;
   2524        case EOpMod:
   2525            ASSERT(node->getUseEmulatedFunction());
   2526            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2527            break;
   2528        case EOpModf:
   2529            outputTriplet(out, visit, "modf(", ", ", ")");
   2530            break;
   2531        case EOpPow:
   2532            outputTriplet(out, visit, "pow(", ", ", ")");
   2533            break;
   2534        case EOpAtan:
   2535            ASSERT(node->getSequence()->size() == 2);  // atan(x) is a unary operator
   2536            ASSERT(node->getUseEmulatedFunction());
   2537            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2538            break;
   2539        case EOpMin:
   2540            outputTriplet(out, visit, "min(", ", ", ")");
   2541            break;
   2542        case EOpMax:
   2543            outputTriplet(out, visit, "max(", ", ", ")");
   2544            break;
   2545        case EOpClamp:
   2546            outputTriplet(out, visit, "clamp(", ", ", ")");
   2547            break;
   2548        case EOpMix:
   2549        {
   2550            TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
   2551            if (lastParamNode->getType().getBasicType() == EbtBool)
   2552            {
   2553                // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType
   2554                // y, genBType a)",
   2555                // so use emulated version.
   2556                ASSERT(node->getUseEmulatedFunction());
   2557                writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2558            }
   2559            else
   2560            {
   2561                outputTriplet(out, visit, "lerp(", ", ", ")");
   2562            }
   2563            break;
   2564        }
   2565        case EOpStep:
   2566            outputTriplet(out, visit, "step(", ", ", ")");
   2567            break;
   2568        case EOpSmoothstep:
   2569            outputTriplet(out, visit, "smoothstep(", ", ", ")");
   2570            break;
   2571        case EOpFma:
   2572            outputTriplet(out, visit, "mad(", ", ", ")");
   2573            break;
   2574        case EOpFrexp:
   2575        case EOpLdexp:
   2576            ASSERT(node->getUseEmulatedFunction());
   2577            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2578            break;
   2579        case EOpDistance:
   2580            outputTriplet(out, visit, "distance(", ", ", ")");
   2581            break;
   2582        case EOpDot:
   2583            outputTriplet(out, visit, "dot(", ", ", ")");
   2584            break;
   2585        case EOpCross:
   2586            outputTriplet(out, visit, "cross(", ", ", ")");
   2587            break;
   2588        case EOpFaceforward:
   2589            ASSERT(node->getUseEmulatedFunction());
   2590            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2591            break;
   2592        case EOpReflect:
   2593            outputTriplet(out, visit, "reflect(", ", ", ")");
   2594            break;
   2595        case EOpRefract:
   2596            outputTriplet(out, visit, "refract(", ", ", ")");
   2597            break;
   2598        case EOpOuterProduct:
   2599            ASSERT(node->getUseEmulatedFunction());
   2600            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2601            break;
   2602        case EOpMatrixCompMult:
   2603            outputTriplet(out, visit, "(", " * ", ")");
   2604            break;
   2605        case EOpBitfieldExtract:
   2606        case EOpBitfieldInsert:
   2607        case EOpUaddCarry:
   2608        case EOpUsubBorrow:
   2609        case EOpUmulExtended:
   2610        case EOpImulExtended:
   2611            ASSERT(node->getUseEmulatedFunction());
   2612            writeEmulatedFunctionTriplet(out, visit, node->getFunction());
   2613            break;
   2614        case EOpDFdx:
   2615            if (mInsideDiscontinuousLoop || mOutputLod0Function)
   2616            {
   2617                outputTriplet(out, visit, "(", "", ", 0.0)");
   2618            }
   2619            else
   2620            {
   2621                outputTriplet(out, visit, "ddx(", "", ")");
   2622            }
   2623            break;
   2624        case EOpDFdy:
   2625            if (mInsideDiscontinuousLoop || mOutputLod0Function)
   2626            {
   2627                outputTriplet(out, visit, "(", "", ", 0.0)");
   2628            }
   2629            else
   2630            {
   2631                outputTriplet(out, visit, "ddy(", "", ")");
   2632            }
   2633            break;
   2634        case EOpFwidth:
   2635            if (mInsideDiscontinuousLoop || mOutputLod0Function)
   2636            {
   2637                outputTriplet(out, visit, "(", "", ", 0.0)");
   2638            }
   2639            else
   2640            {
   2641                outputTriplet(out, visit, "fwidth(", "", ")");
   2642            }
   2643            break;
   2644        case EOpBarrier:
   2645            // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the
   2646            // cheapest *WithGroupSync() function, without any functionality loss, but
   2647            // with the potential for severe performance loss.
   2648            outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")");
   2649            break;
   2650        case EOpMemoryBarrierShared:
   2651            outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")");
   2652            break;
   2653        case EOpMemoryBarrierAtomicCounter:
   2654        case EOpMemoryBarrierBuffer:
   2655        case EOpMemoryBarrierImage:
   2656            outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")");
   2657            break;
   2658        case EOpGroupMemoryBarrier:
   2659        case EOpMemoryBarrier:
   2660            outputTriplet(out, visit, "AllMemoryBarrier(", "", ")");
   2661            break;
   2662 
   2663        // Single atomic function calls without return value.
   2664        // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value).
   2665        case EOpAtomicAdd:
   2666        case EOpAtomicMin:
   2667        case EOpAtomicMax:
   2668        case EOpAtomicAnd:
   2669        case EOpAtomicOr:
   2670        case EOpAtomicXor:
   2671        // The parameter 'original_value' of InterlockedExchange(dest, value, original_value)
   2672        // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not
   2673        // optional.
   2674        // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange
   2675        // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange
   2676        // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest,
   2677        // compare_value, value) should all be modified into the form of "int temp; temp =
   2678        // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest,
   2679        // compare_value, value);" in the intermediate tree before traversing outputHLSL.
   2680        case EOpAtomicExchange:
   2681        case EOpAtomicCompSwap:
   2682        {
   2683            ASSERT(node->getChildCount() > 1);
   2684            TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped();
   2685            if (IsInShaderStorageBlock(memNode))
   2686            {
   2687                // Atomic memory functions for SSBO.
   2688                // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|.
   2689                mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp());
   2690                // Write the rest argument list to |out|.
   2691                for (size_t i = 1; i < node->getChildCount(); i++)
   2692                {
   2693                    out << ", ";
   2694                    TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped();
   2695                    if (IsInShaderStorageBlock(argument))
   2696                    {
   2697                        mSSBOOutputHLSL->outputLoadFunctionCall(argument);
   2698                    }
   2699                    else
   2700                    {
   2701                        argument->traverse(this);
   2702                    }
   2703                }
   2704 
   2705                out << ")";
   2706                return false;
   2707            }
   2708            else
   2709            {
   2710                // Atomic memory functions for shared variable.
   2711                if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap)
   2712                {
   2713                    outputTriplet(out, visit,
   2714                                  GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",",
   2715                                  ")");
   2716                }
   2717                else
   2718                {
   2719                    UNREACHABLE();
   2720                }
   2721            }
   2722 
   2723            break;
   2724        }
   2725    }
   2726 
   2727    return true;
   2728 }
   2729 
   2730 void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
   2731 {
   2732    out << "if (";
   2733 
   2734    node->getCondition()->traverse(this);
   2735 
   2736    out << ")\n";
   2737 
   2738    outputLineDirective(out, node->getLine().first_line);
   2739 
   2740    bool discard = false;
   2741 
   2742    if (node->getTrueBlock())
   2743    {
   2744        // The trueBlock child node will output braces.
   2745        node->getTrueBlock()->traverse(this);
   2746 
   2747        // Detect true discard
   2748        discard = (discard || FindDiscard::search(node->getTrueBlock()));
   2749    }
   2750    else
   2751    {
   2752        // TODO(oetuaho): Check if the semicolon inside is necessary.
   2753        // It's there as a result of conservative refactoring of the output.
   2754        out << "{;}\n";
   2755    }
   2756 
   2757    outputLineDirective(out, node->getLine().first_line);
   2758 
   2759    if (node->getFalseBlock())
   2760    {
   2761        out << "else\n";
   2762 
   2763        outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
   2764 
   2765        // The falseBlock child node will output braces.
   2766        node->getFalseBlock()->traverse(this);
   2767 
   2768        outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
   2769 
   2770        // Detect false discard
   2771        discard = (discard || FindDiscard::search(node->getFalseBlock()));
   2772    }
   2773 
   2774    // ANGLE issue 486: Detect problematic conditional discard
   2775    if (discard)
   2776    {
   2777        mUsesDiscardRewriting = true;
   2778    }
   2779 }
   2780 
   2781 bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
   2782 {
   2783    // Ternary ops should have been already converted to something else in the AST. HLSL ternary
   2784    // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
   2785    UNREACHABLE();
   2786    return false;
   2787 }
   2788 
   2789 bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
   2790 {
   2791    TInfoSinkBase &out = getInfoSink();
   2792 
   2793    ASSERT(mInsideFunction);
   2794 
   2795    // D3D errors when there is a gradient operation in a loop in an unflattened if.
   2796    if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
   2797    {
   2798        out << "FLATTEN ";
   2799    }
   2800 
   2801    writeIfElse(out, node);
   2802 
   2803    return false;
   2804 }
   2805 
   2806 bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
   2807 {
   2808    TInfoSinkBase &out = getInfoSink();
   2809 
   2810    ASSERT(node->getStatementList());
   2811    if (visit == PreVisit)
   2812    {
   2813        node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics));
   2814    }
   2815    outputTriplet(out, visit, "switch (", ") ", "");
   2816    // The curly braces get written when visiting the statementList block.
   2817    return true;
   2818 }
   2819 
   2820 bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
   2821 {
   2822    TInfoSinkBase &out = getInfoSink();
   2823 
   2824    if (node->hasCondition())
   2825    {
   2826        outputTriplet(out, visit, "case (", "", "):\n");
   2827        return true;
   2828    }
   2829    else
   2830    {
   2831        out << "default:\n";
   2832        return false;
   2833    }
   2834 }
   2835 
   2836 void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
   2837 {
   2838    TInfoSinkBase &out = getInfoSink();
   2839    writeConstantUnion(out, node->getType(), node->getConstantValue());
   2840 }
   2841 
   2842 bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
   2843 {
   2844    mNestedLoopDepth++;
   2845 
   2846    bool wasDiscontinuous = mInsideDiscontinuousLoop;
   2847    mInsideDiscontinuousLoop =
   2848        mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
   2849 
   2850    TInfoSinkBase &out = getInfoSink();
   2851 
   2852    if (mOutputType == SH_HLSL_3_0_OUTPUT)
   2853    {
   2854        if (handleExcessiveLoop(out, node))
   2855        {
   2856            mInsideDiscontinuousLoop = wasDiscontinuous;
   2857            mNestedLoopDepth--;
   2858 
   2859            return false;
   2860        }
   2861    }
   2862 
   2863    const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
   2864    if (node->getType() == ELoopDoWhile)
   2865    {
   2866        out << "{" << unroll << " do\n";
   2867 
   2868        outputLineDirective(out, node->getLine().first_line);
   2869    }
   2870    else
   2871    {
   2872        out << "{" << unroll << " for(";
   2873 
   2874        if (node->getInit())
   2875        {
   2876            node->getInit()->traverse(this);
   2877        }
   2878 
   2879        out << "; ";
   2880 
   2881        if (node->getCondition())
   2882        {
   2883            node->getCondition()->traverse(this);
   2884        }
   2885 
   2886        out << "; ";
   2887 
   2888        if (node->getExpression())
   2889        {
   2890            node->getExpression()->traverse(this);
   2891        }
   2892 
   2893        out << ")\n";
   2894 
   2895        outputLineDirective(out, node->getLine().first_line);
   2896    }
   2897 
   2898    if (node->getBody())
   2899    {
   2900        // The loop body node will output braces.
   2901        node->getBody()->traverse(this);
   2902    }
   2903    else
   2904    {
   2905        // TODO(oetuaho): Check if the semicolon inside is necessary.
   2906        // It's there as a result of conservative refactoring of the output.
   2907        out << "{;}\n";
   2908    }
   2909 
   2910    outputLineDirective(out, node->getLine().first_line);
   2911 
   2912    if (node->getType() == ELoopDoWhile)
   2913    {
   2914        outputLineDirective(out, node->getCondition()->getLine().first_line);
   2915        out << "while (";
   2916 
   2917        node->getCondition()->traverse(this);
   2918 
   2919        out << ");\n";
   2920    }
   2921 
   2922    out << "}\n";
   2923 
   2924    mInsideDiscontinuousLoop = wasDiscontinuous;
   2925    mNestedLoopDepth--;
   2926 
   2927    return false;
   2928 }
   2929 
   2930 bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
   2931 {
   2932    if (visit == PreVisit)
   2933    {
   2934        TInfoSinkBase &out = getInfoSink();
   2935 
   2936        switch (node->getFlowOp())
   2937        {
   2938            case EOpKill:
   2939                out << "discard";
   2940                break;
   2941            case EOpBreak:
   2942                if (mNestedLoopDepth > 1)
   2943                {
   2944                    mUsesNestedBreak = true;
   2945                }
   2946 
   2947                if (mExcessiveLoopIndex)
   2948                {
   2949                    out << "{Break";
   2950                    mExcessiveLoopIndex->traverse(this);
   2951                    out << " = true; break;}\n";
   2952                }
   2953                else
   2954                {
   2955                    out << "break";
   2956                }
   2957                break;
   2958            case EOpContinue:
   2959                out << "continue";
   2960                break;
   2961            case EOpReturn:
   2962                if (node->getExpression())
   2963                {
   2964                    ASSERT(!mInsideMain);
   2965                    out << "return ";
   2966                    if (IsInShaderStorageBlock(node->getExpression()))
   2967                    {
   2968                        mSSBOOutputHLSL->outputLoadFunctionCall(node->getExpression());
   2969                        return false;
   2970                    }
   2971                }
   2972                else
   2973                {
   2974                    if (mInsideMain && shaderNeedsGenerateOutput())
   2975                    {
   2976                        out << "return " << generateOutputCall();
   2977                    }
   2978                    else
   2979                    {
   2980                        out << "return";
   2981                    }
   2982                }
   2983                break;
   2984            default:
   2985                UNREACHABLE();
   2986        }
   2987    }
   2988 
   2989    return true;
   2990 }
   2991 
   2992 // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
   2993 // (The D3D documentation says 255 iterations, but the compiler complains at anything more than
   2994 // 254).
   2995 bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
   2996 {
   2997    const int MAX_LOOP_ITERATIONS = 254;
   2998 
   2999    // Parse loops of the form:
   3000    // for(int index = initial; index [comparator] limit; index += increment)
   3001    TIntermSymbol *index = nullptr;
   3002    TOperator comparator = EOpNull;
   3003    int initial          = 0;
   3004    int limit            = 0;
   3005    int increment        = 0;
   3006 
   3007    // Parse index name and intial value
   3008    if (node->getInit())
   3009    {
   3010        TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
   3011 
   3012        if (init)
   3013        {
   3014            TIntermSequence *sequence = init->getSequence();
   3015            TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
   3016 
   3017            if (variable && variable->getQualifier() == EvqTemporary)
   3018            {
   3019                TIntermBinary *assign = variable->getAsBinaryNode();
   3020 
   3021                if (assign != nullptr && assign->getOp() == EOpInitialize)
   3022                {
   3023                    TIntermSymbol *symbol          = assign->getLeft()->getAsSymbolNode();
   3024                    TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
   3025 
   3026                    if (symbol && constant)
   3027                    {
   3028                        if (constant->getBasicType() == EbtInt && constant->isScalar())
   3029                        {
   3030                            index   = symbol;
   3031                            initial = constant->getIConst(0);
   3032                        }
   3033                    }
   3034                }
   3035            }
   3036        }
   3037    }
   3038 
   3039    // Parse comparator and limit value
   3040    if (index != nullptr && node->getCondition())
   3041    {
   3042        TIntermBinary *test = node->getCondition()->getAsBinaryNode();
   3043 
   3044        if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId())
   3045        {
   3046            TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
   3047 
   3048            if (constant)
   3049            {
   3050                if (constant->getBasicType() == EbtInt && constant->isScalar())
   3051                {
   3052                    comparator = test->getOp();
   3053                    limit      = constant->getIConst(0);
   3054                }
   3055            }
   3056        }
   3057    }
   3058 
   3059    // Parse increment
   3060    if (index != nullptr && comparator != EOpNull && node->getExpression())
   3061    {
   3062        TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
   3063        TIntermUnary *unaryTerminal   = node->getExpression()->getAsUnaryNode();
   3064 
   3065        if (binaryTerminal)
   3066        {
   3067            TOperator op                   = binaryTerminal->getOp();
   3068            TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
   3069 
   3070            if (constant)
   3071            {
   3072                if (constant->getBasicType() == EbtInt && constant->isScalar())
   3073                {
   3074                    int value = constant->getIConst(0);
   3075 
   3076                    switch (op)
   3077                    {
   3078                        case EOpAddAssign:
   3079                            increment = value;
   3080                            break;
   3081                        case EOpSubAssign:
   3082                            increment = -value;
   3083                            break;
   3084                        default:
   3085                            UNIMPLEMENTED();
   3086                    }
   3087                }
   3088            }
   3089        }
   3090        else if (unaryTerminal)
   3091        {
   3092            TOperator op = unaryTerminal->getOp();
   3093 
   3094            switch (op)
   3095            {
   3096                case EOpPostIncrement:
   3097                    increment = 1;
   3098                    break;
   3099                case EOpPostDecrement:
   3100                    increment = -1;
   3101                    break;
   3102                case EOpPreIncrement:
   3103                    increment = 1;
   3104                    break;
   3105                case EOpPreDecrement:
   3106                    increment = -1;
   3107                    break;
   3108                default:
   3109                    UNIMPLEMENTED();
   3110            }
   3111        }
   3112    }
   3113 
   3114    if (index != nullptr && comparator != EOpNull && increment != 0)
   3115    {
   3116        if (comparator == EOpLessThanEqual)
   3117        {
   3118            comparator = EOpLessThan;
   3119            limit += 1;
   3120        }
   3121 
   3122        if (comparator == EOpLessThan)
   3123        {
   3124            int iterations = (limit - initial) / increment;
   3125 
   3126            if (iterations <= MAX_LOOP_ITERATIONS)
   3127            {
   3128                return false;  // Not an excessive loop
   3129            }
   3130 
   3131            TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
   3132            mExcessiveLoopIndex         = index;
   3133 
   3134            out << "{int ";
   3135            index->traverse(this);
   3136            out << ";\n"
   3137                   "bool Break";
   3138            index->traverse(this);
   3139            out << " = false;\n";
   3140 
   3141            bool firstLoopFragment = true;
   3142 
   3143            while (iterations > 0)
   3144            {
   3145                int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
   3146 
   3147                if (!firstLoopFragment)
   3148                {
   3149                    out << "if (!Break";
   3150                    index->traverse(this);
   3151                    out << ") {\n";
   3152                }
   3153 
   3154                if (iterations <= MAX_LOOP_ITERATIONS)  // Last loop fragment
   3155                {
   3156                    mExcessiveLoopIndex = nullptr;  // Stops setting the Break flag
   3157                }
   3158 
   3159                // for(int index = initial; index < clampedLimit; index += increment)
   3160                const char *unroll =
   3161                    mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
   3162 
   3163                out << unroll << " for(";
   3164                index->traverse(this);
   3165                out << " = ";
   3166                out << initial;
   3167 
   3168                out << "; ";
   3169                index->traverse(this);
   3170                out << " < ";
   3171                out << clampedLimit;
   3172 
   3173                out << "; ";
   3174                index->traverse(this);
   3175                out << " += ";
   3176                out << increment;
   3177                out << ")\n";
   3178 
   3179                outputLineDirective(out, node->getLine().first_line);
   3180                out << "{\n";
   3181 
   3182                if (node->getBody())
   3183                {
   3184                    node->getBody()->traverse(this);
   3185                }
   3186 
   3187                outputLineDirective(out, node->getLine().first_line);
   3188                out << ";}\n";
   3189 
   3190                if (!firstLoopFragment)
   3191                {
   3192                    out << "}\n";
   3193                }
   3194 
   3195                firstLoopFragment = false;
   3196 
   3197                initial += MAX_LOOP_ITERATIONS * increment;
   3198                iterations -= MAX_LOOP_ITERATIONS;
   3199            }
   3200 
   3201            out << "}";
   3202 
   3203            mExcessiveLoopIndex = restoreIndex;
   3204 
   3205            return true;
   3206        }
   3207        else
   3208            UNIMPLEMENTED();
   3209    }
   3210 
   3211    return false;  // Not handled as an excessive loop
   3212 }
   3213 
   3214 void OutputHLSL::outputTriplet(TInfoSinkBase &out,
   3215                               Visit visit,
   3216                               const char *preString,
   3217                               const char *inString,
   3218                               const char *postString)
   3219 {
   3220    if (visit == PreVisit)
   3221    {
   3222        out << preString;
   3223    }
   3224    else if (visit == InVisit)
   3225    {
   3226        out << inString;
   3227    }
   3228    else if (visit == PostVisit)
   3229    {
   3230        out << postString;
   3231    }
   3232 }
   3233 
   3234 void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
   3235 {
   3236    if (mCompileOptions.lineDirectives && line > 0)
   3237    {
   3238        out << "\n";
   3239        out << "#line " << line;
   3240 
   3241        if (mSourcePath)
   3242        {
   3243            out << " \"" << mSourcePath << "\"";
   3244        }
   3245 
   3246        out << "\n";
   3247    }
   3248 }
   3249 
   3250 void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out)
   3251 {
   3252    const TType &type    = param->getType();
   3253    TQualifier qualifier = type.getQualifier();
   3254 
   3255    TString nameStr = DecorateVariableIfNeeded(*param);
   3256    ASSERT(nameStr != "");  // HLSL demands named arguments, also for prototypes
   3257 
   3258    if (IsSampler(type.getBasicType()))
   3259    {
   3260        if (mOutputType == SH_HLSL_4_1_OUTPUT)
   3261        {
   3262            // Samplers are passed as indices to the sampler array.
   3263            ASSERT(qualifier != EvqParamOut && qualifier != EvqParamInOut);
   3264            out << "const uint " << nameStr << ArrayString(type);
   3265            return;
   3266        }
   3267        if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
   3268        {
   3269            out << QualifierString(qualifier) << " " << TextureString(type.getBasicType())
   3270                << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier)
   3271                << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr
   3272                << ArrayString(type);
   3273            return;
   3274        }
   3275    }
   3276 
   3277    // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the
   3278    // buffer offset.
   3279    if (IsAtomicCounter(type.getBasicType()))
   3280    {
   3281        out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int "
   3282            << nameStr << "_offset";
   3283    }
   3284    else
   3285    {
   3286        out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
   3287            << ArrayString(type);
   3288    }
   3289 
   3290    // If the structure parameter contains samplers, they need to be passed into the function as
   3291    // separate parameters. HLSL doesn't natively support samplers in structs.
   3292    if (type.isStructureContainingSamplers())
   3293    {
   3294        ASSERT(qualifier != EvqParamOut && qualifier != EvqParamInOut);
   3295        TVector<const TVariable *> samplerSymbols;
   3296        std::string namePrefix = "angle";
   3297        namePrefix += nameStr.c_str();
   3298        type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr,
   3299                                  mSymbolTable);
   3300        for (const TVariable *sampler : samplerSymbols)
   3301        {
   3302            const TType &samplerType = sampler->getType();
   3303            if (mOutputType == SH_HLSL_4_1_OUTPUT)
   3304            {
   3305                out << ", const uint " << sampler->name() << ArrayString(samplerType);
   3306            }
   3307            else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
   3308            {
   3309                ASSERT(IsSampler(samplerType.getBasicType()));
   3310                out << ", " << QualifierString(qualifier) << " "
   3311                    << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name()
   3312                    << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " "
   3313                    << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name()
   3314                    << ArrayString(samplerType);
   3315            }
   3316            else
   3317            {
   3318                ASSERT(IsSampler(samplerType.getBasicType()));
   3319                out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " "
   3320                    << sampler->name() << ArrayString(samplerType);
   3321            }
   3322        }
   3323    }
   3324 }
   3325 
   3326 TString OutputHLSL::zeroInitializer(const TType &type) const
   3327 {
   3328    TString string;
   3329 
   3330    size_t size = type.getObjectSize();
   3331    if (size >= kZeroCount)
   3332    {
   3333        mUseZeroArray = true;
   3334    }
   3335    string = GetZeroInitializer(size).c_str();
   3336 
   3337    return "{" + string + "}";
   3338 }
   3339 
   3340 void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
   3341 {
   3342    // Array constructors should have been already pruned from the code.
   3343    ASSERT(!node->getType().isArray());
   3344 
   3345    if (visit == PreVisit)
   3346    {
   3347        TString constructorName;
   3348        if (node->getBasicType() == EbtStruct)
   3349        {
   3350            constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
   3351        }
   3352        else
   3353        {
   3354            constructorName =
   3355                mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
   3356        }
   3357        out << constructorName << "(";
   3358    }
   3359    else if (visit == InVisit)
   3360    {
   3361        out << ", ";
   3362    }
   3363    else if (visit == PostVisit)
   3364    {
   3365        out << ")";
   3366    }
   3367 }
   3368 
   3369 const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
   3370                                                     const TType &type,
   3371                                                     const TConstantUnion *const constUnion)
   3372 {
   3373    ASSERT(!type.isArray());
   3374 
   3375    const TConstantUnion *constUnionIterated = constUnion;
   3376 
   3377    const TStructure *structure = type.getStruct();
   3378    if (structure)
   3379    {
   3380        out << mStructureHLSL->addStructConstructor(*structure) << "(";
   3381 
   3382        const TFieldList &fields = structure->fields();
   3383 
   3384        for (size_t i = 0; i < fields.size(); i++)
   3385        {
   3386            const TType *fieldType = fields[i]->type();
   3387            constUnionIterated     = writeConstantUnion(out, *fieldType, constUnionIterated);
   3388 
   3389            if (i != fields.size() - 1)
   3390            {
   3391                out << ", ";
   3392            }
   3393        }
   3394 
   3395        out << ")";
   3396    }
   3397    else
   3398    {
   3399        size_t size    = type.getObjectSize();
   3400        bool writeType = size > 1;
   3401 
   3402        if (writeType)
   3403        {
   3404            out << TypeString(type) << "(";
   3405        }
   3406        constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
   3407        if (writeType)
   3408        {
   3409            out << ")";
   3410        }
   3411    }
   3412 
   3413    return constUnionIterated;
   3414 }
   3415 
   3416 void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out,
   3417                                              Visit visit,
   3418                                              const TFunction *function)
   3419 {
   3420    if (visit == PreVisit)
   3421    {
   3422        ASSERT(function != nullptr);
   3423        BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, function->name().data());
   3424        out << "(";
   3425    }
   3426    else
   3427    {
   3428        outputTriplet(out, visit, nullptr, ", ", ")");
   3429    }
   3430 }
   3431 
   3432 bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out,
   3433                                            TIntermSymbol *symbolNode,
   3434                                            TIntermTyped *expression)
   3435 {
   3436    ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty);
   3437    const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName());
   3438 
   3439    if (symbolInInitializer)
   3440    {
   3441        // Type already printed
   3442        out << "t" + str(mUniqueIndex) + " = ";
   3443        expression->traverse(this);
   3444        out << ", ";
   3445        symbolNode->traverse(this);
   3446        out << " = t" + str(mUniqueIndex);
   3447 
   3448        mUniqueIndex++;
   3449        return true;
   3450    }
   3451 
   3452    return false;
   3453 }
   3454 
   3455 bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
   3456                                             TIntermSymbol *symbolNode,
   3457                                             TIntermTyped *initializer)
   3458 {
   3459    if (initializer->hasConstantValue())
   3460    {
   3461        symbolNode->traverse(this);
   3462        out << ArrayString(symbolNode->getType());
   3463        out << " = {";
   3464        writeConstantUnionArray(out, initializer->getConstantValue(),
   3465                                initializer->getType().getObjectSize());
   3466        out << "}";
   3467        return true;
   3468    }
   3469    return false;
   3470 }
   3471 
   3472 TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
   3473 {
   3474    const TFieldList &fields = structure.fields();
   3475 
   3476    for (const auto &eqFunction : mStructEqualityFunctions)
   3477    {
   3478        if (eqFunction->structure == &structure)
   3479        {
   3480            return eqFunction->functionName;
   3481        }
   3482    }
   3483 
   3484    const TString &structNameString = StructNameString(structure);
   3485 
   3486    StructEqualityFunction *function = new StructEqualityFunction();
   3487    function->structure              = &structure;
   3488    function->functionName           = "angle_eq_" + structNameString;
   3489 
   3490    TInfoSinkBase fnOut;
   3491 
   3492    fnOut << "bool " << function->functionName << "(" << structNameString << " a, "
   3493          << structNameString + " b)\n"
   3494          << "{\n"
   3495             "    return ";
   3496 
   3497    for (size_t i = 0; i < fields.size(); i++)
   3498    {
   3499        const TField *field    = fields[i];
   3500        const TType *fieldType = field->type();
   3501 
   3502        const TString &fieldNameA = "a." + Decorate(field->name());
   3503        const TString &fieldNameB = "b." + Decorate(field->name());
   3504 
   3505        if (i > 0)
   3506        {
   3507            fnOut << " && ";
   3508        }
   3509 
   3510        fnOut << "(";
   3511        outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
   3512        fnOut << fieldNameA;
   3513        outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
   3514        fnOut << fieldNameB;
   3515        outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
   3516        fnOut << ")";
   3517    }
   3518 
   3519    fnOut << ";\n"
   3520          << "}\n";
   3521 
   3522    function->functionDefinition = fnOut.c_str();
   3523 
   3524    mStructEqualityFunctions.push_back(function);
   3525    mEqualityFunctions.push_back(function);
   3526 
   3527    return function->functionName;
   3528 }
   3529 
   3530 TString OutputHLSL::addArrayEqualityFunction(const TType &type)
   3531 {
   3532    for (const auto &eqFunction : mArrayEqualityFunctions)
   3533    {
   3534        if (eqFunction->type == type)
   3535        {
   3536            return eqFunction->functionName;
   3537        }
   3538    }
   3539 
   3540    TType elementType(type);
   3541    elementType.toArrayElementType();
   3542 
   3543    ArrayHelperFunction *function = new ArrayHelperFunction();
   3544    function->type                = type;
   3545 
   3546    function->functionName = ArrayHelperFunctionName("angle_eq", type);
   3547 
   3548    TInfoSinkBase fnOut;
   3549 
   3550    const TString &typeName = TypeString(type);
   3551    fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
   3552          << ", " << typeName << " b" << ArrayString(type) << ")\n"
   3553          << "{\n"
   3554             "    for (int i = 0; i < "
   3555          << type.getOutermostArraySize()
   3556          << "; ++i)\n"
   3557             "    {\n"
   3558             "        if (";
   3559 
   3560    outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
   3561    fnOut << "a[i]";
   3562    outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
   3563    fnOut << "b[i]";
   3564    outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
   3565 
   3566    fnOut << ") { return false; }\n"
   3567             "    }\n"
   3568             "    return true;\n"
   3569             "}\n";
   3570 
   3571    function->functionDefinition = fnOut.c_str();
   3572 
   3573    mArrayEqualityFunctions.push_back(function);
   3574    mEqualityFunctions.push_back(function);
   3575 
   3576    return function->functionName;
   3577 }
   3578 
   3579 TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
   3580 {
   3581    for (const auto &assignFunction : mArrayAssignmentFunctions)
   3582    {
   3583        if (assignFunction.type == type)
   3584        {
   3585            return assignFunction.functionName;
   3586        }
   3587    }
   3588 
   3589    TType elementType(type);
   3590    elementType.toArrayElementType();
   3591 
   3592    ArrayHelperFunction function;
   3593    function.type = type;
   3594 
   3595    function.functionName = ArrayHelperFunctionName("angle_assign", type);
   3596 
   3597    TInfoSinkBase fnOut;
   3598 
   3599    const TString &typeName = TypeString(type);
   3600    fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
   3601          << ", " << typeName << " b" << ArrayString(type) << ")\n"
   3602          << "{\n"
   3603             "    for (int i = 0; i < "
   3604          << type.getOutermostArraySize()
   3605          << "; ++i)\n"
   3606             "    {\n"
   3607             "        ";
   3608 
   3609    outputAssign(PreVisit, elementType, fnOut);
   3610    fnOut << "a[i]";
   3611    outputAssign(InVisit, elementType, fnOut);
   3612    fnOut << "b[i]";
   3613    outputAssign(PostVisit, elementType, fnOut);
   3614 
   3615    fnOut << ";\n"
   3616             "    }\n"
   3617             "}\n";
   3618 
   3619    function.functionDefinition = fnOut.c_str();
   3620 
   3621    mArrayAssignmentFunctions.push_back(function);
   3622 
   3623    return function.functionName;
   3624 }
   3625 
   3626 TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
   3627 {
   3628    for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
   3629    {
   3630        if (constructIntoFunction.type == type)
   3631        {
   3632            return constructIntoFunction.functionName;
   3633        }
   3634    }
   3635 
   3636    TType elementType(type);
   3637    elementType.toArrayElementType();
   3638 
   3639    ArrayHelperFunction function;
   3640    function.type = type;
   3641 
   3642    function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
   3643 
   3644    TInfoSinkBase fnOut;
   3645 
   3646    const TString &typeName = TypeString(type);
   3647    fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
   3648    for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
   3649    {
   3650        fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
   3651    }
   3652    fnOut << ")\n"
   3653             "{\n";
   3654 
   3655    for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
   3656    {
   3657        fnOut << "    ";
   3658        outputAssign(PreVisit, elementType, fnOut);
   3659        fnOut << "a[" << i << "]";
   3660        outputAssign(InVisit, elementType, fnOut);
   3661        fnOut << "b" << i;
   3662        outputAssign(PostVisit, elementType, fnOut);
   3663        fnOut << ";\n";
   3664    }
   3665    fnOut << "}\n";
   3666 
   3667    function.functionDefinition = fnOut.c_str();
   3668 
   3669    mArrayConstructIntoFunctions.push_back(function);
   3670 
   3671    return function.functionName;
   3672 }
   3673 
   3674 void OutputHLSL::ensureStructDefined(const TType &type)
   3675 {
   3676    const TStructure *structure = type.getStruct();
   3677    if (structure)
   3678    {
   3679        ASSERT(type.getBasicType() == EbtStruct);
   3680        mStructureHLSL->ensureStructDefined(*structure);
   3681    }
   3682 }
   3683 
   3684 bool OutputHLSL::shaderNeedsGenerateOutput() const
   3685 {
   3686    return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER;
   3687 }
   3688 
   3689 const char *OutputHLSL::generateOutputCall() const
   3690 {
   3691    if (mShaderType == GL_VERTEX_SHADER)
   3692    {
   3693        return "generateOutput(input)";
   3694    }
   3695    else
   3696    {
   3697        return "generateOutput()";
   3698    }
   3699 }
   3700 }  // namespace sh