LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - OutputHLSL.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1439 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 49 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2002-2014 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 <algorithm>
      10             : #include <cfloat>
      11             : #include <stdio.h>
      12             : 
      13             : #include "common/angleutils.h"
      14             : #include "common/debug.h"
      15             : #include "common/utilities.h"
      16             : #include "compiler/translator/BuiltInFunctionEmulator.h"
      17             : #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
      18             : #include "compiler/translator/FlagStd140Structs.h"
      19             : #include "compiler/translator/InfoSink.h"
      20             : #include "compiler/translator/NodeSearch.h"
      21             : #include "compiler/translator/RemoveSwitchFallThrough.h"
      22             : #include "compiler/translator/SearchSymbol.h"
      23             : #include "compiler/translator/StructureHLSL.h"
      24             : #include "compiler/translator/TextureFunctionHLSL.h"
      25             : #include "compiler/translator/TranslatorHLSL.h"
      26             : #include "compiler/translator/UniformHLSL.h"
      27             : #include "compiler/translator/UtilsHLSL.h"
      28             : #include "compiler/translator/blocklayout.h"
      29             : #include "compiler/translator/util.h"
      30             : 
      31             : namespace sh
      32             : {
      33             : 
      34           0 : void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
      35             : {
      36             :     // This is known not to work for NaN on all drivers but make the best effort to output NaNs
      37             :     // regardless.
      38           0 :     if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 &&
      39           0 :         mOutputType == SH_HLSL_4_1_OUTPUT)
      40             :     {
      41           0 :         out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)";
      42             :     }
      43             :     else
      44             :     {
      45           0 :         out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
      46             :     }
      47           0 : }
      48             : 
      49           0 : void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
      50             : {
      51           0 :     ASSERT(constUnion != nullptr);
      52           0 :     switch (constUnion->getType())
      53             :     {
      54             :         case EbtFloat:
      55           0 :             writeFloat(out, constUnion->getFConst());
      56           0 :             break;
      57             :         case EbtInt:
      58           0 :             out << constUnion->getIConst();
      59           0 :             break;
      60             :         case EbtUInt:
      61           0 :             out << constUnion->getUConst();
      62           0 :             break;
      63             :         case EbtBool:
      64           0 :             out << constUnion->getBConst();
      65           0 :             break;
      66             :         default:
      67           0 :             UNREACHABLE();
      68             :     }
      69           0 : }
      70             : 
      71           0 : const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
      72             :                                                           const TConstantUnion *const constUnion,
      73             :                                                           const size_t size)
      74             : {
      75           0 :     const TConstantUnion *constUnionIterated = constUnion;
      76           0 :     for (size_t i = 0; i < size; i++, constUnionIterated++)
      77             :     {
      78           0 :         writeSingleConstant(out, constUnionIterated);
      79             : 
      80           0 :         if (i != size - 1)
      81             :         {
      82           0 :             out << ", ";
      83             :         }
      84             :     }
      85           0 :     return constUnionIterated;
      86             : }
      87             : 
      88           0 : OutputHLSL::OutputHLSL(sh::GLenum shaderType,
      89             :                        int shaderVersion,
      90             :                        const TExtensionBehavior &extensionBehavior,
      91             :                        const char *sourcePath,
      92             :                        ShShaderOutput outputType,
      93             :                        int numRenderTargets,
      94             :                        const std::vector<Uniform> &uniforms,
      95           0 :                        ShCompileOptions compileOptions)
      96             :     : TIntermTraverser(true, true, true),
      97             :       mShaderType(shaderType),
      98             :       mShaderVersion(shaderVersion),
      99             :       mExtensionBehavior(extensionBehavior),
     100             :       mSourcePath(sourcePath),
     101             :       mOutputType(outputType),
     102             :       mCompileOptions(compileOptions),
     103             :       mNumRenderTargets(numRenderTargets),
     104           0 :       mCurrentFunctionMetadata(nullptr)
     105             : {
     106           0 :     mInsideFunction = false;
     107             : 
     108           0 :     mUsesFragColor = false;
     109           0 :     mUsesFragData = false;
     110           0 :     mUsesDepthRange = false;
     111           0 :     mUsesFragCoord = false;
     112           0 :     mUsesPointCoord = false;
     113           0 :     mUsesFrontFacing = false;
     114           0 :     mUsesPointSize = false;
     115           0 :     mUsesInstanceID = false;
     116           0 :     mUsesVertexID                = false;
     117           0 :     mUsesFragDepth = false;
     118           0 :     mUsesXor = false;
     119           0 :     mUsesDiscardRewriting = false;
     120           0 :     mUsesNestedBreak = false;
     121           0 :     mRequiresIEEEStrictCompiling = false;
     122             : 
     123           0 :     mUniqueIndex = 0;
     124             : 
     125           0 :     mOutputLod0Function = false;
     126           0 :     mInsideDiscontinuousLoop = false;
     127           0 :     mNestedLoopDepth = 0;
     128             : 
     129           0 :     mExcessiveLoopIndex = NULL;
     130             : 
     131           0 :     mStructureHLSL = new StructureHLSL;
     132           0 :     mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
     133           0 :     mTextureFunctionHLSL = new TextureFunctionHLSL;
     134             : 
     135           0 :     if (mOutputType == SH_HLSL_3_0_OUTPUT)
     136             :     {
     137             :         // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
     138             :         // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust.
     139             :         // In both cases total 3 uniform registers need to be reserved.
     140           0 :         mUniformHLSL->reserveUniformRegisters(3);
     141             :     }
     142             : 
     143             :     // Reserve registers for the default uniform block and driver constants
     144           0 :     mUniformHLSL->reserveInterfaceBlockRegisters(2);
     145           0 : }
     146             : 
     147           0 : OutputHLSL::~OutputHLSL()
     148             : {
     149           0 :     SafeDelete(mStructureHLSL);
     150           0 :     SafeDelete(mUniformHLSL);
     151           0 :     SafeDelete(mTextureFunctionHLSL);
     152           0 :     for (auto &eqFunction : mStructEqualityFunctions)
     153             :     {
     154           0 :         SafeDelete(eqFunction);
     155             :     }
     156           0 :     for (auto &eqFunction : mArrayEqualityFunctions)
     157             :     {
     158           0 :         SafeDelete(eqFunction);
     159             :     }
     160           0 : }
     161             : 
     162           0 : void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
     163             : {
     164           0 :     const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
     165           0 :     makeFlaggedStructMaps(flaggedStructs);
     166             : 
     167           0 :     BuiltInFunctionEmulator builtInFunctionEmulator;
     168           0 :     InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
     169           0 :     if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0)
     170             :     {
     171           0 :         InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator,
     172           0 :                                                            mShaderVersion);
     173             :     }
     174             : 
     175           0 :     builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
     176             : 
     177             :     // Now that we are done changing the AST, do the analyses need for HLSL generation
     178           0 :     CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink);
     179           0 :     ASSERT(success == CallDAG::INITDAG_SUCCESS);
     180           0 :     mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
     181             : 
     182             :     // Output the body and footer first to determine what has to go in the header
     183           0 :     mInfoSinkStack.push(&mBody);
     184           0 :     treeRoot->traverse(this);
     185           0 :     mInfoSinkStack.pop();
     186             : 
     187           0 :     mInfoSinkStack.push(&mFooter);
     188           0 :     mInfoSinkStack.pop();
     189             : 
     190           0 :     mInfoSinkStack.push(&mHeader);
     191           0 :     header(mHeader, &builtInFunctionEmulator);
     192           0 :     mInfoSinkStack.pop();
     193             : 
     194           0 :     objSink << mHeader.c_str();
     195           0 :     objSink << mBody.c_str();
     196           0 :     objSink << mFooter.c_str();
     197             : 
     198           0 :     builtInFunctionEmulator.Cleanup();
     199           0 : }
     200             : 
     201           0 : void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs)
     202             : {
     203           0 :     for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++)
     204             :     {
     205           0 :         TIntermTyped *flaggedNode = flaggedStructs[structIndex];
     206             : 
     207           0 :         TInfoSinkBase structInfoSink;
     208           0 :         mInfoSinkStack.push(&structInfoSink);
     209             : 
     210             :         // This will mark the necessary block elements as referenced
     211           0 :         flaggedNode->traverse(this);
     212             : 
     213           0 :         TString structName(structInfoSink.c_str());
     214           0 :         mInfoSinkStack.pop();
     215             : 
     216           0 :         mFlaggedStructOriginalNames[flaggedNode] = structName;
     217             : 
     218           0 :         for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.'))
     219             :         {
     220           0 :             structName.erase(pos, 1);
     221             :         }
     222             : 
     223           0 :         mFlaggedStructMappedNames[flaggedNode] = "map" + structName;
     224             :     }
     225           0 : }
     226             : 
     227           0 : const std::map<std::string, unsigned int> &OutputHLSL::getInterfaceBlockRegisterMap() const
     228             : {
     229           0 :     return mUniformHLSL->getInterfaceBlockRegisterMap();
     230             : }
     231             : 
     232           0 : const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const
     233             : {
     234           0 :     return mUniformHLSL->getUniformRegisterMap();
     235             : }
     236             : 
     237           0 : int OutputHLSL::vectorSize(const TType &type) const
     238             : {
     239           0 :     int elementSize = type.isMatrix() ? type.getCols() : 1;
     240           0 :     unsigned int arraySize = type.isArray() ? type.getArraySize() : 1u;
     241             : 
     242           0 :     return elementSize * arraySize;
     243             : }
     244             : 
     245           0 : TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName)
     246             : {
     247           0 :     TString init;
     248             : 
     249           0 :     TString preIndentString;
     250           0 :     TString fullIndentString;
     251             : 
     252           0 :     for (int spaces = 0; spaces < (indent * 4); spaces++)
     253             :     {
     254           0 :         preIndentString += ' ';
     255             :     }
     256             : 
     257           0 :     for (int spaces = 0; spaces < ((indent+1) * 4); spaces++)
     258             :     {
     259           0 :         fullIndentString += ' ';
     260             :     }
     261             : 
     262           0 :     init += preIndentString + "{\n";
     263             : 
     264           0 :     const TFieldList &fields = structure.fields();
     265           0 :     for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
     266             :     {
     267           0 :         const TField &field = *fields[fieldIndex];
     268           0 :         const TString &fieldName = rhsStructName + "." + Decorate(field.name());
     269           0 :         const TType &fieldType = *field.type();
     270             : 
     271           0 :         if (fieldType.getStruct())
     272             :         {
     273           0 :             init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName);
     274             :         }
     275             :         else
     276             :         {
     277           0 :             init += fullIndentString + fieldName + ",\n";
     278             :         }
     279             :     }
     280             : 
     281           0 :     init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n";
     282             : 
     283           0 :     return init;
     284             : }
     285             : 
     286           0 : void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
     287             : {
     288           0 :     TString varyings;
     289           0 :     TString attributes;
     290           0 :     TString flaggedStructs;
     291             : 
     292           0 :     for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++)
     293             :     {
     294           0 :         TIntermTyped *structNode = flaggedStructIt->first;
     295           0 :         const TString &mappedName = flaggedStructIt->second;
     296           0 :         const TStructure &structure = *structNode->getType().getStruct();
     297           0 :         const TString &originalName = mFlaggedStructOriginalNames[structNode];
     298             : 
     299           0 :         flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n";
     300           0 :         flaggedStructs += structInitializerString(0, structure, originalName);
     301           0 :         flaggedStructs += "\n";
     302             :     }
     303             : 
     304           0 :     for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
     305             :     {
     306           0 :         const TType &type = varying->second->getType();
     307           0 :         const TString &name = varying->second->getSymbol();
     308             : 
     309             :         // Program linking depends on this exact format
     310           0 :         varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " +
     311           0 :                     Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
     312             :     }
     313             : 
     314           0 :     for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
     315             :     {
     316           0 :         const TType &type = attribute->second->getType();
     317           0 :         const TString &name = attribute->second->getSymbol();
     318             : 
     319           0 :         attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n";
     320             :     }
     321             : 
     322           0 :     out << mStructureHLSL->structsHeader();
     323             : 
     324           0 :     mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
     325           0 :     out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
     326             : 
     327           0 :     if (!mEqualityFunctions.empty())
     328             :     {
     329           0 :         out << "\n// Equality functions\n\n";
     330           0 :         for (const auto &eqFunction : mEqualityFunctions)
     331             :         {
     332           0 :             out << eqFunction->functionDefinition << "\n";
     333             :         }
     334             :     }
     335           0 :     if (!mArrayAssignmentFunctions.empty())
     336             :     {
     337           0 :         out << "\n// Assignment functions\n\n";
     338           0 :         for (const auto &assignmentFunction : mArrayAssignmentFunctions)
     339             :         {
     340           0 :             out << assignmentFunction.functionDefinition << "\n";
     341             :         }
     342             :     }
     343           0 :     if (!mArrayConstructIntoFunctions.empty())
     344             :     {
     345           0 :         out << "\n// Array constructor functions\n\n";
     346           0 :         for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
     347             :         {
     348           0 :             out << constructIntoFunction.functionDefinition << "\n";
     349             :         }
     350             :     }
     351             : 
     352           0 :     if (mUsesDiscardRewriting)
     353             :     {
     354           0 :         out << "#define ANGLE_USES_DISCARD_REWRITING\n";
     355             :     }
     356             : 
     357           0 :     if (mUsesNestedBreak)
     358             :     {
     359           0 :         out << "#define ANGLE_USES_NESTED_BREAK\n";
     360             :     }
     361             : 
     362           0 :     if (mRequiresIEEEStrictCompiling)
     363             :     {
     364           0 :         out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n";
     365             :     }
     366             : 
     367             :     out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n"
     368             :            "#define LOOP [loop]\n"
     369             :            "#define FLATTEN [flatten]\n"
     370             :            "#else\n"
     371             :            "#define LOOP\n"
     372             :            "#define FLATTEN\n"
     373           0 :            "#endif\n";
     374             : 
     375           0 :     if (mShaderType == GL_FRAGMENT_SHADER)
     376             :     {
     377           0 :         TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers");
     378           0 :         const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire));
     379             : 
     380           0 :         out << "// Varyings\n";
     381           0 :         out <<  varyings;
     382           0 :         out << "\n";
     383             : 
     384           0 :         if (mShaderVersion >= 300)
     385             :         {
     386           0 :             for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++)
     387             :             {
     388           0 :                 const TString &variableName = outputVariableIt->first;
     389           0 :                 const TType &variableType = outputVariableIt->second->getType();
     390             : 
     391           0 :                 out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) +
     392           0 :                        " = " + initializer(variableType) + ";\n";
     393             :             }
     394             :         }
     395             :         else
     396             :         {
     397           0 :             const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
     398             : 
     399           0 :             out << "static float4 gl_Color[" << numColorValues << "] =\n"
     400           0 :                    "{\n";
     401           0 :             for (unsigned int i = 0; i < numColorValues; i++)
     402             :             {
     403           0 :                 out << "    float4(0, 0, 0, 0)";
     404           0 :                 if (i + 1 != numColorValues)
     405             :                 {
     406           0 :                     out << ",";
     407             :                 }
     408           0 :                 out << "\n";
     409             :             }
     410             : 
     411           0 :             out << "};\n";
     412             :         }
     413             : 
     414           0 :         if (mUsesFragDepth)
     415             :         {
     416           0 :             out << "static float gl_Depth = 0.0;\n";
     417             :         }
     418             : 
     419           0 :         if (mUsesFragCoord)
     420             :         {
     421           0 :             out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
     422             :         }
     423             : 
     424           0 :         if (mUsesPointCoord)
     425             :         {
     426           0 :             out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
     427             :         }
     428             : 
     429           0 :         if (mUsesFrontFacing)
     430             :         {
     431           0 :             out << "static bool gl_FrontFacing = false;\n";
     432             :         }
     433             : 
     434           0 :         out << "\n";
     435             : 
     436           0 :         if (mUsesDepthRange)
     437             :         {
     438             :             out << "struct gl_DepthRangeParameters\n"
     439             :                    "{\n"
     440             :                    "    float near;\n"
     441             :                    "    float far;\n"
     442             :                    "    float diff;\n"
     443             :                    "};\n"
     444           0 :                    "\n";
     445             :         }
     446             : 
     447           0 :         if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
     448             :         {
     449             :             out << "cbuffer DriverConstants : register(b1)\n"
     450           0 :                    "{\n";
     451             : 
     452           0 :             if (mUsesDepthRange)
     453             :             {
     454           0 :                 out << "    float3 dx_DepthRange : packoffset(c0);\n";
     455             :             }
     456             : 
     457           0 :             if (mUsesFragCoord)
     458             :             {
     459           0 :                 out << "    float4 dx_ViewCoords : packoffset(c1);\n";
     460             :             }
     461             : 
     462           0 :             if (mUsesFragCoord || mUsesFrontFacing)
     463             :             {
     464           0 :                 out << "    float3 dx_DepthFront : packoffset(c2);\n";
     465             :             }
     466             : 
     467           0 :             if (mUsesFragCoord)
     468             :             {
     469             :                 // dx_ViewScale is only used in the fragment shader to correct
     470             :                 // the value for glFragCoord if necessary
     471           0 :                 out << "    float2 dx_ViewScale : packoffset(c3);\n";
     472             :             }
     473             : 
     474           0 :             if (mOutputType == SH_HLSL_4_1_OUTPUT)
     475             :             {
     476           0 :                 mUniformHLSL->samplerMetadataUniforms(out, "c4");
     477             :             }
     478             : 
     479           0 :             out << "};\n";
     480             :         }
     481             :         else
     482             :         {
     483           0 :             if (mUsesDepthRange)
     484             :             {
     485           0 :                 out << "uniform float3 dx_DepthRange : register(c0);";
     486             :             }
     487             : 
     488           0 :             if (mUsesFragCoord)
     489             :             {
     490           0 :                 out << "uniform float4 dx_ViewCoords : register(c1);\n";
     491             :             }
     492             : 
     493           0 :             if (mUsesFragCoord || mUsesFrontFacing)
     494             :             {
     495           0 :                 out << "uniform float3 dx_DepthFront : register(c2);\n";
     496             :             }
     497             :         }
     498             : 
     499           0 :         out << "\n";
     500             : 
     501           0 :         if (mUsesDepthRange)
     502             :         {
     503             :             out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
     504           0 :                    "\n";
     505             :         }
     506             : 
     507           0 :         if (!flaggedStructs.empty())
     508             :         {
     509           0 :             out << "// Std140 Structures accessed by value\n";
     510           0 :             out << "\n";
     511           0 :             out << flaggedStructs;
     512           0 :             out << "\n";
     513             :         }
     514             : 
     515           0 :         if (usingMRTExtension && mNumRenderTargets > 1)
     516             :         {
     517           0 :             out << "#define GL_USES_MRT\n";
     518             :         }
     519             : 
     520           0 :         if (mUsesFragColor)
     521             :         {
     522           0 :             out << "#define GL_USES_FRAG_COLOR\n";
     523             :         }
     524             : 
     525           0 :         if (mUsesFragData)
     526             :         {
     527           0 :             out << "#define GL_USES_FRAG_DATA\n";
     528             :         }
     529             :     }
     530             :     else   // Vertex shader
     531             :     {
     532           0 :         out << "// Attributes\n";
     533           0 :         out <<  attributes;
     534             :         out << "\n"
     535           0 :                "static float4 gl_Position = float4(0, 0, 0, 0);\n";
     536             : 
     537           0 :         if (mUsesPointSize)
     538             :         {
     539           0 :             out << "static float gl_PointSize = float(1);\n";
     540             :         }
     541             : 
     542           0 :         if (mUsesInstanceID)
     543             :         {
     544           0 :             out << "static int gl_InstanceID;";
     545             :         }
     546             : 
     547           0 :         if (mUsesVertexID)
     548             :         {
     549           0 :             out << "static int gl_VertexID;";
     550             :         }
     551             : 
     552             :         out << "\n"
     553           0 :                "// Varyings\n";
     554           0 :         out <<  varyings;
     555           0 :         out << "\n";
     556             : 
     557           0 :         if (mUsesDepthRange)
     558             :         {
     559             :             out << "struct gl_DepthRangeParameters\n"
     560             :                    "{\n"
     561             :                    "    float near;\n"
     562             :                    "    float far;\n"
     563             :                    "    float diff;\n"
     564             :                    "};\n"
     565           0 :                    "\n";
     566             :         }
     567             : 
     568           0 :         if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
     569             :         {
     570             :             out << "cbuffer DriverConstants : register(b1)\n"
     571           0 :                     "{\n";
     572             : 
     573           0 :             if (mUsesDepthRange)
     574             :             {
     575           0 :                 out << "    float3 dx_DepthRange : packoffset(c0);\n";
     576             :             }
     577             : 
     578             :             // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
     579             :             // shaders. However, we declare it for all shaders (including Feature Level 10+).
     580             :             // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
     581             :             // if it's unused.
     582           0 :             out << "    float4 dx_ViewAdjust : packoffset(c1);\n";
     583           0 :             out << "    float2 dx_ViewCoords : packoffset(c2);\n";
     584           0 :             out << "    float2 dx_ViewScale  : packoffset(c3);\n";
     585             : 
     586           0 :             if (mOutputType == SH_HLSL_4_1_OUTPUT)
     587             :             {
     588           0 :                 mUniformHLSL->samplerMetadataUniforms(out, "c4");
     589             :             }
     590             : 
     591             :             out << "};\n"
     592           0 :                    "\n";
     593             :         }
     594             :         else
     595             :         {
     596           0 :             if (mUsesDepthRange)
     597             :             {
     598           0 :                 out << "uniform float3 dx_DepthRange : register(c0);\n";
     599             :             }
     600             : 
     601           0 :             out << "uniform float4 dx_ViewAdjust : register(c1);\n";
     602             :             out << "uniform float2 dx_ViewCoords : register(c2);\n"
     603           0 :                    "\n";
     604             :         }
     605             : 
     606           0 :         if (mUsesDepthRange)
     607             :         {
     608             :             out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
     609           0 :                    "\n";
     610             :         }
     611             : 
     612           0 :         if (!flaggedStructs.empty())
     613             :         {
     614           0 :             out << "// Std140 Structures accessed by value\n";
     615           0 :             out << "\n";
     616           0 :             out << flaggedStructs;
     617           0 :             out << "\n";
     618             :         }
     619             :     }
     620             : 
     621             :     bool getDimensionsIgnoresBaseLevel =
     622           0 :         (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
     623           0 :     mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel);
     624             : 
     625           0 :     if (mUsesFragCoord)
     626             :     {
     627           0 :         out << "#define GL_USES_FRAG_COORD\n";
     628             :     }
     629             : 
     630           0 :     if (mUsesPointCoord)
     631             :     {
     632           0 :         out << "#define GL_USES_POINT_COORD\n";
     633             :     }
     634             : 
     635           0 :     if (mUsesFrontFacing)
     636             :     {
     637           0 :         out << "#define GL_USES_FRONT_FACING\n";
     638             :     }
     639             : 
     640           0 :     if (mUsesPointSize)
     641             :     {
     642           0 :         out << "#define GL_USES_POINT_SIZE\n";
     643             :     }
     644             : 
     645           0 :     if (mUsesFragDepth)
     646             :     {
     647           0 :         out << "#define GL_USES_FRAG_DEPTH\n";
     648             :     }
     649             : 
     650           0 :     if (mUsesDepthRange)
     651             :     {
     652           0 :         out << "#define GL_USES_DEPTH_RANGE\n";
     653             :     }
     654             : 
     655           0 :     if (mUsesXor)
     656             :     {
     657             :         out << "bool xor(bool p, bool q)\n"
     658             :                "{\n"
     659             :                "    return (p || q) && !(p && q);\n"
     660             :                "}\n"
     661           0 :                "\n";
     662             :     }
     663             : 
     664           0 :     builtInFunctionEmulator->OutputEmulatedFunctions(out);
     665           0 : }
     666             : 
     667           0 : void OutputHLSL::visitSymbol(TIntermSymbol *node)
     668             : {
     669           0 :     TInfoSinkBase &out = getInfoSink();
     670             : 
     671             :     // Handle accessing std140 structs by value
     672           0 :     if (mFlaggedStructMappedNames.count(node) > 0)
     673             :     {
     674           0 :         out << mFlaggedStructMappedNames[node];
     675           0 :         return;
     676             :     }
     677             : 
     678           0 :     TString name = node->getSymbol();
     679             : 
     680           0 :     if (name == "gl_DepthRange")
     681             :     {
     682           0 :         mUsesDepthRange = true;
     683           0 :         out << name;
     684             :     }
     685             :     else
     686             :     {
     687           0 :         TQualifier qualifier = node->getQualifier();
     688             : 
     689           0 :         if (qualifier == EvqUniform)
     690             :         {
     691           0 :             const TType &nodeType = node->getType();
     692           0 :             const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
     693             : 
     694           0 :             if (interfaceBlock)
     695             :             {
     696           0 :                 mReferencedInterfaceBlocks[interfaceBlock->name()] = node;
     697             :             }
     698             :             else
     699             :             {
     700           0 :                 mReferencedUniforms[name] = node;
     701             :             }
     702             : 
     703           0 :             ensureStructDefined(nodeType);
     704             : 
     705           0 :             const TName &nameWithMetadata = node->getName();
     706           0 :             out << DecorateUniform(nameWithMetadata, nodeType);
     707             :         }
     708           0 :         else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
     709             :         {
     710           0 :             mReferencedAttributes[name] = node;
     711           0 :             out << Decorate(name);
     712             :         }
     713           0 :         else if (IsVarying(qualifier))
     714             :         {
     715           0 :             mReferencedVaryings[name] = node;
     716           0 :             out << Decorate(name);
     717             :         }
     718           0 :         else if (qualifier == EvqFragmentOut)
     719             :         {
     720           0 :             mReferencedOutputVariables[name] = node;
     721           0 :             out << "out_" << name;
     722             :         }
     723           0 :         else if (qualifier == EvqFragColor)
     724             :         {
     725           0 :             out << "gl_Color[0]";
     726           0 :             mUsesFragColor = true;
     727             :         }
     728           0 :         else if (qualifier == EvqFragData)
     729             :         {
     730           0 :             out << "gl_Color";
     731           0 :             mUsesFragData = true;
     732             :         }
     733           0 :         else if (qualifier == EvqFragCoord)
     734             :         {
     735           0 :             mUsesFragCoord = true;
     736           0 :             out << name;
     737             :         }
     738           0 :         else if (qualifier == EvqPointCoord)
     739             :         {
     740           0 :             mUsesPointCoord = true;
     741           0 :             out << name;
     742             :         }
     743           0 :         else if (qualifier == EvqFrontFacing)
     744             :         {
     745           0 :             mUsesFrontFacing = true;
     746           0 :             out << name;
     747             :         }
     748           0 :         else if (qualifier == EvqPointSize)
     749             :         {
     750           0 :             mUsesPointSize = true;
     751           0 :             out << name;
     752             :         }
     753           0 :         else if (qualifier == EvqInstanceID)
     754             :         {
     755           0 :             mUsesInstanceID = true;
     756           0 :             out << name;
     757             :         }
     758           0 :         else if (qualifier == EvqVertexID)
     759             :         {
     760           0 :             mUsesVertexID = true;
     761           0 :             out << name;
     762             :         }
     763           0 :         else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
     764             :         {
     765           0 :             mUsesFragDepth = true;
     766           0 :             out << "gl_Depth";
     767             :         }
     768             :         else
     769             :         {
     770           0 :             out << DecorateIfNeeded(node->getName());
     771             :         }
     772             :     }
     773             : }
     774             : 
     775           0 : void OutputHLSL::visitRaw(TIntermRaw *node)
     776             : {
     777           0 :     getInfoSink() << node->getRawText();
     778           0 : }
     779             : 
     780           0 : void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out)
     781             : {
     782           0 :     if (type.isScalar() && !type.isArray())
     783             :     {
     784           0 :         if (op == EOpEqual)
     785             :         {
     786           0 :             outputTriplet(out, visit, "(", " == ", ")");
     787             :         }
     788             :         else
     789             :         {
     790           0 :             outputTriplet(out, visit, "(", " != ", ")");
     791             :         }
     792             :     }
     793             :     else
     794             :     {
     795           0 :         if (visit == PreVisit && op == EOpNotEqual)
     796             :         {
     797           0 :             out << "!";
     798             :         }
     799             : 
     800           0 :         if (type.isArray())
     801             :         {
     802           0 :             const TString &functionName = addArrayEqualityFunction(type);
     803           0 :             outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
     804             :         }
     805           0 :         else if (type.getBasicType() == EbtStruct)
     806             :         {
     807           0 :             const TStructure &structure = *type.getStruct();
     808           0 :             const TString &functionName = addStructEqualityFunction(structure);
     809           0 :             outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
     810             :         }
     811             :         else
     812             :         {
     813           0 :             ASSERT(type.isMatrix() || type.isVector());
     814           0 :             outputTriplet(out, visit, "all(", " == ", ")");
     815             :         }
     816             :     }
     817           0 : }
     818             : 
     819           0 : bool OutputHLSL::ancestorEvaluatesToSamplerInStruct(Visit visit)
     820             : {
     821             :     // Inside InVisit the current node is already in the path.
     822           0 :     const unsigned int initialN = visit == InVisit ? 1u : 0u;
     823           0 :     for (unsigned int n = initialN; getAncestorNode(n) != nullptr; ++n)
     824             :     {
     825           0 :         TIntermNode *ancestor               = getAncestorNode(n);
     826           0 :         const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
     827           0 :         if (ancestorBinary == nullptr)
     828             :         {
     829           0 :             return false;
     830             :         }
     831           0 :         switch (ancestorBinary->getOp())
     832             :         {
     833             :             case EOpIndexDirectStruct:
     834             :             {
     835           0 :                 const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
     836             :                 const TIntermConstantUnion *index =
     837           0 :                     ancestorBinary->getRight()->getAsConstantUnion();
     838           0 :                 const TField *field = structure->fields()[index->getIConst(0)];
     839           0 :                 if (IsSampler(field->type()->getBasicType()))
     840             :                 {
     841           0 :                     return true;
     842             :                 }
     843           0 :                 break;
     844             :             }
     845             :             case EOpIndexDirect:
     846           0 :                 break;
     847             :             default:
     848             :                 // Returning a sampler from indirect indexing is not supported.
     849           0 :                 return false;
     850             :         }
     851             :     }
     852           0 :     return false;
     853             : }
     854             : 
     855           0 : bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
     856             : {
     857           0 :     TInfoSinkBase &out = getInfoSink();
     858           0 :     if (visit == PostVisit)
     859             :     {
     860           0 :         out << ".";
     861           0 :         node->writeOffsetsAsXYZW(&out);
     862             :     }
     863           0 :     return true;
     864             : }
     865             : 
     866           0 : bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
     867             : {
     868           0 :     TInfoSinkBase &out = getInfoSink();
     869             : 
     870             :     // Handle accessing std140 structs by value
     871           0 :     if (mFlaggedStructMappedNames.count(node) > 0)
     872             :     {
     873           0 :         out << mFlaggedStructMappedNames[node];
     874           0 :         return false;
     875             :     }
     876             : 
     877           0 :     switch (node->getOp())
     878             :     {
     879             :         case EOpComma:
     880           0 :             outputTriplet(out, visit, "(", ", ", ")");
     881           0 :             break;
     882             :         case EOpAssign:
     883           0 :             if (node->getLeft()->isArray())
     884             :             {
     885           0 :                 TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
     886           0 :                 if (rightAgg != nullptr && rightAgg->isConstructor())
     887             :                 {
     888           0 :                     const TString &functionName = addArrayConstructIntoFunction(node->getType());
     889           0 :                     out << functionName << "(";
     890           0 :                     node->getLeft()->traverse(this);
     891           0 :                     TIntermSequence *seq = rightAgg->getSequence();
     892           0 :                     for (auto &arrayElement : *seq)
     893             :                     {
     894           0 :                         out << ", ";
     895           0 :                         arrayElement->traverse(this);
     896             :                     }
     897           0 :                     out << ")";
     898           0 :                     return false;
     899             :                 }
     900             :                 // ArrayReturnValueToOutParameter should have eliminated expressions where a
     901             :                 // function call is assigned.
     902           0 :                 ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
     903             : 
     904           0 :                 const TString &functionName = addArrayAssignmentFunction(node->getType());
     905           0 :                 outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
     906             :             }
     907             :             else
     908             :             {
     909           0 :                 outputTriplet(out, visit, "(", " = ", ")");
     910             :             }
     911           0 :             break;
     912             :         case EOpInitialize:
     913           0 :             if (visit == PreVisit)
     914             :             {
     915           0 :                 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
     916           0 :                 ASSERT(symbolNode);
     917           0 :                 TIntermTyped *expression = node->getRight();
     918             : 
     919             :                 // Global initializers must be constant at this point.
     920           0 :                 ASSERT(symbolNode->getQualifier() != EvqGlobal ||
     921             :                        canWriteAsHLSLLiteral(expression));
     922             : 
     923             :                 // GLSL allows to write things like "float x = x;" where a new variable x is defined
     924             :                 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
     925             :                 // new variable is created before the assignment is evaluated), so we need to
     926             :                 // convert
     927             :                 // this to "float t = x, x = t;".
     928           0 :                 if (writeSameSymbolInitializer(out, symbolNode, expression))
     929             :                 {
     930             :                     // Skip initializing the rest of the expression
     931           0 :                     return false;
     932             :                 }
     933           0 :                 else if (writeConstantInitialization(out, symbolNode, expression))
     934             :                 {
     935           0 :                     return false;
     936             :                 }
     937             :             }
     938           0 :             else if (visit == InVisit)
     939             :             {
     940           0 :                 out << " = ";
     941             :             }
     942           0 :             break;
     943             :         case EOpAddAssign:
     944           0 :             outputTriplet(out, visit, "(", " += ", ")");
     945           0 :             break;
     946             :         case EOpSubAssign:
     947           0 :             outputTriplet(out, visit, "(", " -= ", ")");
     948           0 :             break;
     949             :         case EOpMulAssign:
     950           0 :             outputTriplet(out, visit, "(", " *= ", ")");
     951           0 :             break;
     952             :         case EOpVectorTimesScalarAssign:
     953           0 :             outputTriplet(out, visit, "(", " *= ", ")");
     954           0 :             break;
     955             :         case EOpMatrixTimesScalarAssign:
     956           0 :             outputTriplet(out, visit, "(", " *= ", ")");
     957           0 :             break;
     958             :         case EOpVectorTimesMatrixAssign:
     959           0 :             if (visit == PreVisit)
     960             :             {
     961           0 :                 out << "(";
     962             :             }
     963           0 :             else if (visit == InVisit)
     964             :             {
     965           0 :                 out << " = mul(";
     966           0 :                 node->getLeft()->traverse(this);
     967           0 :                 out << ", transpose(";
     968             :             }
     969             :             else
     970             :             {
     971           0 :                 out << ")))";
     972             :             }
     973           0 :             break;
     974             :         case EOpMatrixTimesMatrixAssign:
     975           0 :             if (visit == PreVisit)
     976             :             {
     977           0 :                 out << "(";
     978             :             }
     979           0 :             else if (visit == InVisit)
     980             :             {
     981           0 :                 out << " = transpose(mul(transpose(";
     982           0 :                 node->getLeft()->traverse(this);
     983           0 :                 out << "), transpose(";
     984             :             }
     985             :             else
     986             :             {
     987           0 :                 out << "))))";
     988             :             }
     989           0 :             break;
     990             :         case EOpDivAssign:
     991           0 :             outputTriplet(out, visit, "(", " /= ", ")");
     992           0 :             break;
     993             :         case EOpIModAssign:
     994           0 :             outputTriplet(out, visit, "(", " %= ", ")");
     995           0 :             break;
     996             :         case EOpBitShiftLeftAssign:
     997           0 :             outputTriplet(out, visit, "(", " <<= ", ")");
     998           0 :             break;
     999             :         case EOpBitShiftRightAssign:
    1000           0 :             outputTriplet(out, visit, "(", " >>= ", ")");
    1001           0 :             break;
    1002             :         case EOpBitwiseAndAssign:
    1003           0 :             outputTriplet(out, visit, "(", " &= ", ")");
    1004           0 :             break;
    1005             :         case EOpBitwiseXorAssign:
    1006           0 :             outputTriplet(out, visit, "(", " ^= ", ")");
    1007           0 :             break;
    1008             :         case EOpBitwiseOrAssign:
    1009           0 :             outputTriplet(out, visit, "(", " |= ", ")");
    1010           0 :             break;
    1011             :         case EOpIndexDirect:
    1012             :         {
    1013           0 :             const TType& leftType = node->getLeft()->getType();
    1014           0 :             if (leftType.isInterfaceBlock())
    1015             :             {
    1016           0 :                 if (visit == PreVisit)
    1017             :                 {
    1018           0 :                     TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock();
    1019           0 :                     const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
    1020           0 :                     mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode();
    1021           0 :                     out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex);
    1022           0 :                     return false;
    1023             :                 }
    1024             :             }
    1025           0 :             else if (ancestorEvaluatesToSamplerInStruct(visit))
    1026             :             {
    1027             :                 // All parts of an expression that access a sampler in a struct need to use _ as
    1028             :                 // separator to access the sampler variable that has been moved out of the struct.
    1029           0 :                 outputTriplet(out, visit, "", "_", "");
    1030             :             }
    1031             :             else
    1032             :             {
    1033           0 :                 outputTriplet(out, visit, "", "[", "]");
    1034             :             }
    1035             :         }
    1036           0 :         break;
    1037             :       case EOpIndexIndirect:
    1038             :         // We do not currently support indirect references to interface blocks
    1039           0 :         ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
    1040           0 :         outputTriplet(out, visit, "", "[", "]");
    1041           0 :         break;
    1042             :       case EOpIndexDirectStruct:
    1043             :         {
    1044           0 :             const TStructure* structure = node->getLeft()->getType().getStruct();
    1045           0 :             const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
    1046           0 :             const TField* field = structure->fields()[index->getIConst(0)];
    1047             : 
    1048             :             // In cases where indexing returns a sampler, we need to access the sampler variable
    1049             :             // that has been moved out of the struct.
    1050           0 :             bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
    1051           0 :             if (visit == PreVisit && indexingReturnsSampler)
    1052             :             {
    1053             :                 // Samplers extracted from structs have "angle" prefix to avoid name conflicts.
    1054             :                 // This prefix is only output at the beginning of the indexing expression, which
    1055             :                 // may have multiple parts.
    1056           0 :                 out << "angle";
    1057             :             }
    1058           0 :             if (!indexingReturnsSampler)
    1059             :             {
    1060             :                 // All parts of an expression that access a sampler in a struct need to use _ as
    1061             :                 // separator to access the sampler variable that has been moved out of the struct.
    1062           0 :                 indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct(visit);
    1063             :             }
    1064           0 :             if (visit == InVisit)
    1065             :             {
    1066           0 :                 if (indexingReturnsSampler)
    1067             :                 {
    1068           0 :                     out << "_" + field->name();
    1069             :                 }
    1070             :                 else
    1071             :                 {
    1072           0 :                     out << "." + DecorateField(field->name(), *structure);
    1073             :                 }
    1074             : 
    1075           0 :                 return false;
    1076             :             }
    1077             :         }
    1078           0 :         break;
    1079             :       case EOpIndexDirectInterfaceBlock:
    1080           0 :         if (visit == InVisit)
    1081             :         {
    1082           0 :             const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
    1083           0 :             const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
    1084           0 :             const TField* field = interfaceBlock->fields()[index->getIConst(0)];
    1085           0 :             out << "." + Decorate(field->name());
    1086             : 
    1087           0 :             return false;
    1088             :         }
    1089           0 :         break;
    1090             :       case EOpAdd:
    1091           0 :           outputTriplet(out, visit, "(", " + ", ")");
    1092           0 :           break;
    1093             :       case EOpSub:
    1094           0 :           outputTriplet(out, visit, "(", " - ", ")");
    1095           0 :           break;
    1096             :       case EOpMul:
    1097           0 :           outputTriplet(out, visit, "(", " * ", ")");
    1098           0 :           break;
    1099             :       case EOpDiv:
    1100           0 :           outputTriplet(out, visit, "(", " / ", ")");
    1101           0 :           break;
    1102             :       case EOpIMod:
    1103           0 :           outputTriplet(out, visit, "(", " % ", ")");
    1104           0 :           break;
    1105             :       case EOpBitShiftLeft:
    1106           0 :           outputTriplet(out, visit, "(", " << ", ")");
    1107           0 :           break;
    1108             :       case EOpBitShiftRight:
    1109           0 :           outputTriplet(out, visit, "(", " >> ", ")");
    1110           0 :           break;
    1111             :       case EOpBitwiseAnd:
    1112           0 :           outputTriplet(out, visit, "(", " & ", ")");
    1113           0 :           break;
    1114             :       case EOpBitwiseXor:
    1115           0 :           outputTriplet(out, visit, "(", " ^ ", ")");
    1116           0 :           break;
    1117             :       case EOpBitwiseOr:
    1118           0 :           outputTriplet(out, visit, "(", " | ", ")");
    1119           0 :           break;
    1120             :       case EOpEqual:
    1121             :       case EOpNotEqual:
    1122           0 :         outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
    1123           0 :         break;
    1124             :       case EOpLessThan:
    1125           0 :           outputTriplet(out, visit, "(", " < ", ")");
    1126           0 :           break;
    1127             :       case EOpGreaterThan:
    1128           0 :           outputTriplet(out, visit, "(", " > ", ")");
    1129           0 :           break;
    1130             :       case EOpLessThanEqual:
    1131           0 :           outputTriplet(out, visit, "(", " <= ", ")");
    1132           0 :           break;
    1133             :       case EOpGreaterThanEqual:
    1134           0 :           outputTriplet(out, visit, "(", " >= ", ")");
    1135           0 :           break;
    1136             :       case EOpVectorTimesScalar:
    1137           0 :           outputTriplet(out, visit, "(", " * ", ")");
    1138           0 :           break;
    1139             :       case EOpMatrixTimesScalar:
    1140           0 :           outputTriplet(out, visit, "(", " * ", ")");
    1141           0 :           break;
    1142             :       case EOpVectorTimesMatrix:
    1143           0 :           outputTriplet(out, visit, "mul(", ", transpose(", "))");
    1144           0 :           break;
    1145             :       case EOpMatrixTimesVector:
    1146           0 :           outputTriplet(out, visit, "mul(transpose(", "), ", ")");
    1147           0 :           break;
    1148             :       case EOpMatrixTimesMatrix:
    1149           0 :           outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
    1150           0 :           break;
    1151             :       case EOpLogicalOr:
    1152             :         // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
    1153           0 :         ASSERT(!node->getRight()->hasSideEffects());
    1154           0 :         outputTriplet(out, visit, "(", " || ", ")");
    1155           0 :         return true;
    1156             :       case EOpLogicalXor:
    1157           0 :         mUsesXor = true;
    1158           0 :         outputTriplet(out, visit, "xor(", ", ", ")");
    1159           0 :         break;
    1160             :       case EOpLogicalAnd:
    1161             :         // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
    1162           0 :         ASSERT(!node->getRight()->hasSideEffects());
    1163           0 :         outputTriplet(out, visit, "(", " && ", ")");
    1164           0 :         return true;
    1165           0 :       default: UNREACHABLE();
    1166             :     }
    1167             : 
    1168           0 :     return true;
    1169             : }
    1170             : 
    1171           0 : bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
    1172             : {
    1173           0 :     TInfoSinkBase &out = getInfoSink();
    1174             : 
    1175           0 :     switch (node->getOp())
    1176             :     {
    1177             :         case EOpNegative:
    1178           0 :             outputTriplet(out, visit, "(-", "", ")");
    1179           0 :             break;
    1180             :         case EOpPositive:
    1181           0 :             outputTriplet(out, visit, "(+", "", ")");
    1182           0 :             break;
    1183             :         case EOpVectorLogicalNot:
    1184           0 :             outputTriplet(out, visit, "(!", "", ")");
    1185           0 :             break;
    1186             :         case EOpLogicalNot:
    1187           0 :             outputTriplet(out, visit, "(!", "", ")");
    1188           0 :             break;
    1189             :         case EOpBitwiseNot:
    1190           0 :             outputTriplet(out, visit, "(~", "", ")");
    1191           0 :             break;
    1192             :         case EOpPostIncrement:
    1193           0 :             outputTriplet(out, visit, "(", "", "++)");
    1194           0 :             break;
    1195             :         case EOpPostDecrement:
    1196           0 :             outputTriplet(out, visit, "(", "", "--)");
    1197           0 :             break;
    1198             :         case EOpPreIncrement:
    1199           0 :             outputTriplet(out, visit, "(++", "", ")");
    1200           0 :             break;
    1201             :         case EOpPreDecrement:
    1202           0 :             outputTriplet(out, visit, "(--", "", ")");
    1203           0 :             break;
    1204             :         case EOpRadians:
    1205           0 :             outputTriplet(out, visit, "radians(", "", ")");
    1206           0 :             break;
    1207             :         case EOpDegrees:
    1208           0 :             outputTriplet(out, visit, "degrees(", "", ")");
    1209           0 :             break;
    1210             :         case EOpSin:
    1211           0 :             outputTriplet(out, visit, "sin(", "", ")");
    1212           0 :             break;
    1213             :         case EOpCos:
    1214           0 :             outputTriplet(out, visit, "cos(", "", ")");
    1215           0 :             break;
    1216             :         case EOpTan:
    1217           0 :             outputTriplet(out, visit, "tan(", "", ")");
    1218           0 :             break;
    1219             :         case EOpAsin:
    1220           0 :             outputTriplet(out, visit, "asin(", "", ")");
    1221           0 :             break;
    1222             :         case EOpAcos:
    1223           0 :             outputTriplet(out, visit, "acos(", "", ")");
    1224           0 :             break;
    1225             :         case EOpAtan:
    1226           0 :             outputTriplet(out, visit, "atan(", "", ")");
    1227           0 :             break;
    1228             :         case EOpSinh:
    1229           0 :             outputTriplet(out, visit, "sinh(", "", ")");
    1230           0 :             break;
    1231             :         case EOpCosh:
    1232           0 :             outputTriplet(out, visit, "cosh(", "", ")");
    1233           0 :             break;
    1234             :         case EOpTanh:
    1235           0 :             outputTriplet(out, visit, "tanh(", "", ")");
    1236           0 :             break;
    1237             :       case EOpAsinh:
    1238           0 :         ASSERT(node->getUseEmulatedFunction());
    1239           0 :         writeEmulatedFunctionTriplet(out, visit, "asinh(");
    1240           0 :         break;
    1241             :       case EOpAcosh:
    1242           0 :         ASSERT(node->getUseEmulatedFunction());
    1243           0 :         writeEmulatedFunctionTriplet(out, visit, "acosh(");
    1244           0 :         break;
    1245             :       case EOpAtanh:
    1246           0 :         ASSERT(node->getUseEmulatedFunction());
    1247           0 :         writeEmulatedFunctionTriplet(out, visit, "atanh(");
    1248           0 :         break;
    1249             :       case EOpExp:
    1250           0 :           outputTriplet(out, visit, "exp(", "", ")");
    1251           0 :           break;
    1252             :       case EOpLog:
    1253           0 :           outputTriplet(out, visit, "log(", "", ")");
    1254           0 :           break;
    1255             :       case EOpExp2:
    1256           0 :           outputTriplet(out, visit, "exp2(", "", ")");
    1257           0 :           break;
    1258             :       case EOpLog2:
    1259           0 :           outputTriplet(out, visit, "log2(", "", ")");
    1260           0 :           break;
    1261             :       case EOpSqrt:
    1262           0 :           outputTriplet(out, visit, "sqrt(", "", ")");
    1263           0 :           break;
    1264             :       case EOpInverseSqrt:
    1265           0 :           outputTriplet(out, visit, "rsqrt(", "", ")");
    1266           0 :           break;
    1267             :       case EOpAbs:
    1268           0 :           outputTriplet(out, visit, "abs(", "", ")");
    1269           0 :           break;
    1270             :       case EOpSign:
    1271           0 :           outputTriplet(out, visit, "sign(", "", ")");
    1272           0 :           break;
    1273             :       case EOpFloor:
    1274           0 :           outputTriplet(out, visit, "floor(", "", ")");
    1275           0 :           break;
    1276             :       case EOpTrunc:
    1277           0 :           outputTriplet(out, visit, "trunc(", "", ")");
    1278           0 :           break;
    1279             :       case EOpRound:
    1280           0 :           outputTriplet(out, visit, "round(", "", ")");
    1281           0 :           break;
    1282             :       case EOpRoundEven:
    1283           0 :         ASSERT(node->getUseEmulatedFunction());
    1284           0 :         writeEmulatedFunctionTriplet(out, visit, "roundEven(");
    1285           0 :         break;
    1286             :       case EOpCeil:
    1287           0 :           outputTriplet(out, visit, "ceil(", "", ")");
    1288           0 :           break;
    1289             :       case EOpFract:
    1290           0 :           outputTriplet(out, visit, "frac(", "", ")");
    1291           0 :           break;
    1292             :       case EOpIsNan:
    1293           0 :           if (node->getUseEmulatedFunction())
    1294           0 :               writeEmulatedFunctionTriplet(out, visit, "isnan(");
    1295             :           else
    1296           0 :               outputTriplet(out, visit, "isnan(", "", ")");
    1297           0 :           mRequiresIEEEStrictCompiling = true;
    1298           0 :           break;
    1299             :       case EOpIsInf:
    1300           0 :           outputTriplet(out, visit, "isinf(", "", ")");
    1301           0 :           break;
    1302             :       case EOpFloatBitsToInt:
    1303           0 :           outputTriplet(out, visit, "asint(", "", ")");
    1304           0 :           break;
    1305             :       case EOpFloatBitsToUint:
    1306           0 :           outputTriplet(out, visit, "asuint(", "", ")");
    1307           0 :           break;
    1308             :       case EOpIntBitsToFloat:
    1309           0 :           outputTriplet(out, visit, "asfloat(", "", ")");
    1310           0 :           break;
    1311             :       case EOpUintBitsToFloat:
    1312           0 :           outputTriplet(out, visit, "asfloat(", "", ")");
    1313           0 :           break;
    1314             :       case EOpPackSnorm2x16:
    1315           0 :         ASSERT(node->getUseEmulatedFunction());
    1316           0 :         writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
    1317           0 :         break;
    1318             :       case EOpPackUnorm2x16:
    1319           0 :         ASSERT(node->getUseEmulatedFunction());
    1320           0 :         writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
    1321           0 :         break;
    1322             :       case EOpPackHalf2x16:
    1323           0 :         ASSERT(node->getUseEmulatedFunction());
    1324           0 :         writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
    1325           0 :         break;
    1326             :       case EOpUnpackSnorm2x16:
    1327           0 :         ASSERT(node->getUseEmulatedFunction());
    1328           0 :         writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
    1329           0 :         break;
    1330             :       case EOpUnpackUnorm2x16:
    1331           0 :         ASSERT(node->getUseEmulatedFunction());
    1332           0 :         writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
    1333           0 :         break;
    1334             :       case EOpUnpackHalf2x16:
    1335           0 :         ASSERT(node->getUseEmulatedFunction());
    1336           0 :         writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
    1337           0 :         break;
    1338             :       case EOpLength:
    1339           0 :           outputTriplet(out, visit, "length(", "", ")");
    1340           0 :           break;
    1341             :       case EOpNormalize:
    1342           0 :           outputTriplet(out, visit, "normalize(", "", ")");
    1343           0 :           break;
    1344             :       case EOpDFdx:
    1345           0 :         if(mInsideDiscontinuousLoop || mOutputLod0Function)
    1346             :         {
    1347           0 :             outputTriplet(out, visit, "(", "", ", 0.0)");
    1348             :         }
    1349             :         else
    1350             :         {
    1351           0 :             outputTriplet(out, visit, "ddx(", "", ")");
    1352             :         }
    1353           0 :         break;
    1354             :       case EOpDFdy:
    1355           0 :         if(mInsideDiscontinuousLoop || mOutputLod0Function)
    1356             :         {
    1357           0 :             outputTriplet(out, visit, "(", "", ", 0.0)");
    1358             :         }
    1359             :         else
    1360             :         {
    1361           0 :             outputTriplet(out, visit, "ddy(", "", ")");
    1362             :         }
    1363           0 :         break;
    1364             :       case EOpFwidth:
    1365           0 :         if(mInsideDiscontinuousLoop || mOutputLod0Function)
    1366             :         {
    1367           0 :             outputTriplet(out, visit, "(", "", ", 0.0)");
    1368             :         }
    1369             :         else
    1370             :         {
    1371           0 :             outputTriplet(out, visit, "fwidth(", "", ")");
    1372             :         }
    1373           0 :         break;
    1374             :       case EOpTranspose:
    1375           0 :           outputTriplet(out, visit, "transpose(", "", ")");
    1376           0 :           break;
    1377             :       case EOpDeterminant:
    1378           0 :           outputTriplet(out, visit, "determinant(transpose(", "", "))");
    1379           0 :           break;
    1380             :       case EOpInverse:
    1381           0 :         ASSERT(node->getUseEmulatedFunction());
    1382           0 :         writeEmulatedFunctionTriplet(out, visit, "inverse(");
    1383           0 :         break;
    1384             : 
    1385             :       case EOpAny:
    1386           0 :           outputTriplet(out, visit, "any(", "", ")");
    1387           0 :           break;
    1388             :       case EOpAll:
    1389           0 :           outputTriplet(out, visit, "all(", "", ")");
    1390           0 :           break;
    1391           0 :       default: UNREACHABLE();
    1392             :     }
    1393             : 
    1394           0 :     return true;
    1395             : }
    1396             : 
    1397           0 : TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
    1398             : {
    1399           0 :     if (node->getAsSymbolNode())
    1400             :     {
    1401           0 :         return node->getAsSymbolNode()->getSymbol();
    1402             :     }
    1403           0 :     TIntermBinary *nodeBinary = node->getAsBinaryNode();
    1404           0 :     switch (nodeBinary->getOp())
    1405             :     {
    1406             :         case EOpIndexDirect:
    1407             :         {
    1408           0 :             int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
    1409             : 
    1410           0 :             TInfoSinkBase prefixSink;
    1411           0 :             prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
    1412           0 :             return TString(prefixSink.c_str());
    1413             :         }
    1414             :         case EOpIndexDirectStruct:
    1415             :         {
    1416           0 :             TStructure *s       = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
    1417           0 :             int index           = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
    1418           0 :             const TField *field = s->fields()[index];
    1419             : 
    1420           0 :             TInfoSinkBase prefixSink;
    1421           0 :             prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
    1422           0 :                        << field->name();
    1423           0 :             return TString(prefixSink.c_str());
    1424             :         }
    1425             :         default:
    1426           0 :             UNREACHABLE();
    1427             :             return TString("");
    1428             :     }
    1429             : }
    1430             : 
    1431           0 : bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
    1432             : {
    1433           0 :     TInfoSinkBase &out = getInfoSink();
    1434             : 
    1435           0 :     if (mInsideFunction)
    1436             :     {
    1437           0 :         outputLineDirective(out, node->getLine().first_line);
    1438           0 :         out << "{\n";
    1439             :     }
    1440             : 
    1441           0 :     for (TIntermSequence::iterator sit = node->getSequence()->begin();
    1442           0 :          sit != node->getSequence()->end(); sit++)
    1443             :     {
    1444           0 :         outputLineDirective(out, (*sit)->getLine().first_line);
    1445             : 
    1446           0 :         (*sit)->traverse(this);
    1447             : 
    1448             :         // Don't output ; after case labels, they're terminated by :
    1449             :         // This is needed especially since outputting a ; after a case statement would turn empty
    1450             :         // case statements into non-empty case statements, disallowing fall-through from them.
    1451             :         // Also no need to output ; after if statements or sequences. This is done just for
    1452             :         // code clarity.
    1453           0 :         if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
    1454           0 :             (*sit)->getAsBlock() == nullptr)
    1455           0 :             out << ";\n";
    1456             :     }
    1457             : 
    1458           0 :     if (mInsideFunction)
    1459             :     {
    1460           0 :         outputLineDirective(out, node->getLine().last_line);
    1461           0 :         out << "}\n";
    1462             :     }
    1463             : 
    1464           0 :     return false;
    1465             : }
    1466             : 
    1467           0 : bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
    1468             : {
    1469           0 :     TInfoSinkBase &out = getInfoSink();
    1470             : 
    1471           0 :     ASSERT(mCurrentFunctionMetadata == nullptr);
    1472             : 
    1473           0 :     size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
    1474           0 :     ASSERT(index != CallDAG::InvalidIndex);
    1475           0 :     mCurrentFunctionMetadata = &mASTMetadataList[index];
    1476             : 
    1477           0 :     out << TypeString(node->getType()) << " ";
    1478             : 
    1479           0 :     TIntermSequence *parameters = node->getFunctionParameters()->getSequence();
    1480             : 
    1481           0 :     if (node->getFunctionSymbolInfo()->isMain())
    1482             :     {
    1483           0 :         out << "gl_main(";
    1484             :     }
    1485             :     else
    1486             :     {
    1487           0 :         out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
    1488           0 :             << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
    1489             :     }
    1490             : 
    1491           0 :     for (unsigned int i = 0; i < parameters->size(); i++)
    1492             :     {
    1493           0 :         TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode();
    1494             : 
    1495           0 :         if (symbol)
    1496             :         {
    1497           0 :             ensureStructDefined(symbol->getType());
    1498             : 
    1499           0 :             out << argumentString(symbol);
    1500             : 
    1501           0 :             if (i < parameters->size() - 1)
    1502             :             {
    1503           0 :                 out << ", ";
    1504             :             }
    1505             :         }
    1506             :         else
    1507           0 :             UNREACHABLE();
    1508             :     }
    1509             : 
    1510           0 :     out << ")\n";
    1511             : 
    1512           0 :     mInsideFunction = true;
    1513             :     // The function body node will output braces.
    1514           0 :     node->getBody()->traverse(this);
    1515           0 :     mInsideFunction = false;
    1516             : 
    1517           0 :     mCurrentFunctionMetadata = nullptr;
    1518             : 
    1519           0 :     bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
    1520           0 :     if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
    1521             :     {
    1522           0 :         ASSERT(!node->getFunctionSymbolInfo()->isMain());
    1523           0 :         mOutputLod0Function = true;
    1524           0 :         node->traverse(this);
    1525           0 :         mOutputLod0Function = false;
    1526             :     }
    1527             : 
    1528           0 :     return false;
    1529             : }
    1530             : 
    1531           0 : bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
    1532             : {
    1533           0 :     TInfoSinkBase &out = getInfoSink();
    1534           0 :     if (visit == PreVisit)
    1535             :     {
    1536           0 :         TIntermSequence *sequence = node->getSequence();
    1537           0 :         TIntermTyped *variable    = (*sequence)[0]->getAsTyped();
    1538           0 :         ASSERT(sequence->size() == 1);
    1539             : 
    1540           0 :         if (variable &&
    1541           0 :             (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal ||
    1542           0 :              variable->getQualifier() == EvqConst))
    1543             :         {
    1544           0 :             ensureStructDefined(variable->getType());
    1545             : 
    1546           0 :             if (!variable->getAsSymbolNode() ||
    1547           0 :                 variable->getAsSymbolNode()->getSymbol() != "")  // Variable declaration
    1548             :             {
    1549           0 :                 if (!mInsideFunction)
    1550             :                 {
    1551           0 :                     out << "static ";
    1552             :                 }
    1553             : 
    1554           0 :                 out << TypeString(variable->getType()) + " ";
    1555             : 
    1556           0 :                 TIntermSymbol *symbol = variable->getAsSymbolNode();
    1557             : 
    1558           0 :                 if (symbol)
    1559             :                 {
    1560           0 :                     symbol->traverse(this);
    1561           0 :                     out << ArrayString(symbol->getType());
    1562           0 :                     out << " = " + initializer(symbol->getType());
    1563             :                 }
    1564             :                 else
    1565             :                 {
    1566           0 :                     variable->traverse(this);
    1567             :                 }
    1568             :             }
    1569           0 :             else if (variable->getAsSymbolNode() &&
    1570           0 :                      variable->getAsSymbolNode()->getSymbol() == "")  // Type (struct) declaration
    1571             :             {
    1572             :                 // Already added to constructor map
    1573             :             }
    1574             :             else
    1575           0 :                 UNREACHABLE();
    1576             :         }
    1577           0 :         else if (variable && IsVaryingOut(variable->getQualifier()))
    1578             :         {
    1579           0 :             for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++)
    1580             :             {
    1581           0 :                 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
    1582             : 
    1583           0 :                 if (symbol)
    1584             :                 {
    1585             :                     // Vertex (output) varyings which are declared but not written to should
    1586             :                     // still be declared to allow successful linking
    1587           0 :                     mReferencedVaryings[symbol->getSymbol()] = symbol;
    1588             :                 }
    1589             :                 else
    1590             :                 {
    1591           0 :                     (*sit)->traverse(this);
    1592             :                 }
    1593             :             }
    1594             :         }
    1595             :     }
    1596           0 :     return false;
    1597             : }
    1598             : 
    1599           0 : bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
    1600             : {
    1601           0 :     TInfoSinkBase &out = getInfoSink();
    1602             : 
    1603           0 :     switch (node->getOp())
    1604             :     {
    1605             :         case EOpInvariantDeclaration:
    1606             :             // Do not do any translation
    1607           0 :             return false;
    1608             :         case EOpPrototype:
    1609           0 :             if (visit == PreVisit)
    1610             :             {
    1611           0 :                 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
    1612             :                 // Skip the prototype if it is not implemented (and thus not used)
    1613           0 :                 if (index == CallDAG::InvalidIndex)
    1614             :                 {
    1615           0 :                     return false;
    1616             :                 }
    1617             : 
    1618           0 :                 TIntermSequence *arguments = node->getSequence();
    1619             : 
    1620             :                 TString name =
    1621           0 :                     DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
    1622           0 :                 out << TypeString(node->getType()) << " " << name
    1623           0 :                     << DisambiguateFunctionName(arguments) << (mOutputLod0Function ? "Lod0(" : "(");
    1624             : 
    1625           0 :                 for (unsigned int i = 0; i < arguments->size(); i++)
    1626             :                 {
    1627           0 :                     TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
    1628             : 
    1629           0 :                     if (symbol)
    1630             :                     {
    1631           0 :                         out << argumentString(symbol);
    1632             : 
    1633           0 :                         if (i < arguments->size() - 1)
    1634             :                         {
    1635           0 :                             out << ", ";
    1636             :                         }
    1637             :                     }
    1638             :                     else
    1639           0 :                         UNREACHABLE();
    1640             :                 }
    1641             : 
    1642           0 :                 out << ");\n";
    1643             : 
    1644             :                 // Also prototype the Lod0 variant if needed
    1645           0 :                 bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
    1646           0 :                 if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
    1647             :                 {
    1648           0 :                     mOutputLod0Function = true;
    1649           0 :                     node->traverse(this);
    1650           0 :                     mOutputLod0Function = false;
    1651             :                 }
    1652             : 
    1653           0 :                 return false;
    1654             :             }
    1655           0 :             break;
    1656             :         case EOpFunctionCall:
    1657             :         {
    1658           0 :             TIntermSequence *arguments = node->getSequence();
    1659             : 
    1660           0 :             bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
    1661           0 :             if (node->isUserDefined())
    1662             :             {
    1663           0 :                 if (node->isArray())
    1664             :                 {
    1665           0 :                     UNIMPLEMENTED();
    1666             :                 }
    1667           0 :                 size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo());
    1668           0 :                 ASSERT(index != CallDAG::InvalidIndex);
    1669           0 :                 lod0 &= mASTMetadataList[index].mNeedsLod0;
    1670             : 
    1671           0 :                 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
    1672           0 :                 out << DisambiguateFunctionName(node->getSequence());
    1673           0 :                 out << (lod0 ? "Lod0(" : "(");
    1674             :             }
    1675           0 :             else if (node->getFunctionSymbolInfo()->getNameObj().isInternal())
    1676             :             {
    1677             :                 // This path is used for internal functions that don't have their definitions in the
    1678             :                 // AST, such as precision emulation functions.
    1679           0 :                 out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
    1680             :             }
    1681             :             else
    1682             :             {
    1683           0 :                 TString name = TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
    1684           0 :                 TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
    1685           0 :                 int coords                  = (*arguments)[1]->getAsTyped()->getNominalSize();
    1686           0 :                 TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction(
    1687           0 :                     name, samplerType, coords, arguments->size(), lod0, mShaderType);
    1688           0 :                 out << textureFunctionName << "(";
    1689             :             }
    1690             : 
    1691           0 :             for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
    1692             :             {
    1693           0 :                 TIntermTyped *typedArg = (*arg)->getAsTyped();
    1694           0 :                 if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
    1695             :                 {
    1696           0 :                     out << "texture_";
    1697           0 :                     (*arg)->traverse(this);
    1698           0 :                     out << ", sampler_";
    1699             :                 }
    1700             : 
    1701           0 :                 (*arg)->traverse(this);
    1702             : 
    1703           0 :                 if (typedArg->getType().isStructureContainingSamplers())
    1704             :                 {
    1705           0 :                     const TType &argType = typedArg->getType();
    1706           0 :                     TVector<TIntermSymbol *> samplerSymbols;
    1707           0 :                     TString structName = samplerNamePrefixFromStruct(typedArg);
    1708           0 :                     argType.createSamplerSymbols("angle_" + structName, "",
    1709           0 :                                                  argType.isArray() ? argType.getArraySize() : 0u,
    1710           0 :                                                  &samplerSymbols, nullptr);
    1711           0 :                     for (const TIntermSymbol *sampler : samplerSymbols)
    1712             :                     {
    1713           0 :                         if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    1714             :                         {
    1715           0 :                             out << ", texture_" << sampler->getSymbol();
    1716           0 :                             out << ", sampler_" << sampler->getSymbol();
    1717             :                         }
    1718             :                         else
    1719             :                         {
    1720             :                             // In case of HLSL 4.1+, this symbol is the sampler index, and in case
    1721             :                             // of D3D9, it's the sampler variable.
    1722           0 :                             out << ", " + sampler->getSymbol();
    1723             :                         }
    1724             :                     }
    1725             :                 }
    1726             : 
    1727           0 :                 if (arg < arguments->end() - 1)
    1728             :                 {
    1729           0 :                     out << ", ";
    1730             :                 }
    1731             :             }
    1732             : 
    1733           0 :             out << ")";
    1734             : 
    1735           0 :             return false;
    1736             :         }
    1737             :         case EOpParameters:
    1738           0 :             outputTriplet(out, visit, "(", ", ", ")\n{\n");
    1739           0 :             break;
    1740             :         case EOpConstructFloat:
    1741           0 :             outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
    1742           0 :             break;
    1743             :         case EOpConstructVec2:
    1744           0 :             outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
    1745           0 :             break;
    1746             :         case EOpConstructVec3:
    1747           0 :             outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
    1748           0 :             break;
    1749             :         case EOpConstructVec4:
    1750           0 :             outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
    1751           0 :             break;
    1752             :         case EOpConstructBool:
    1753           0 :             outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
    1754           0 :             break;
    1755             :         case EOpConstructBVec2:
    1756           0 :             outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
    1757           0 :             break;
    1758             :         case EOpConstructBVec3:
    1759           0 :             outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
    1760           0 :             break;
    1761             :         case EOpConstructBVec4:
    1762           0 :             outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
    1763           0 :             break;
    1764             :         case EOpConstructInt:
    1765           0 :             outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
    1766           0 :             break;
    1767             :         case EOpConstructIVec2:
    1768           0 :             outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
    1769           0 :             break;
    1770             :         case EOpConstructIVec3:
    1771           0 :             outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
    1772           0 :             break;
    1773             :         case EOpConstructIVec4:
    1774           0 :             outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
    1775           0 :             break;
    1776             :         case EOpConstructUInt:
    1777           0 :             outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
    1778           0 :             break;
    1779             :         case EOpConstructUVec2:
    1780           0 :             outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
    1781           0 :             break;
    1782             :         case EOpConstructUVec3:
    1783           0 :             outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
    1784           0 :             break;
    1785             :         case EOpConstructUVec4:
    1786           0 :             outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
    1787           0 :             break;
    1788             :         case EOpConstructMat2:
    1789           0 :             outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
    1790           0 :             break;
    1791             :         case EOpConstructMat2x3:
    1792           0 :             outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
    1793           0 :             break;
    1794             :         case EOpConstructMat2x4:
    1795           0 :             outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
    1796           0 :             break;
    1797             :         case EOpConstructMat3x2:
    1798           0 :             outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
    1799           0 :             break;
    1800             :         case EOpConstructMat3:
    1801           0 :             outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
    1802           0 :             break;
    1803             :         case EOpConstructMat3x4:
    1804           0 :             outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
    1805           0 :             break;
    1806             :         case EOpConstructMat4x2:
    1807           0 :             outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
    1808           0 :             break;
    1809             :         case EOpConstructMat4x3:
    1810           0 :             outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
    1811           0 :             break;
    1812             :         case EOpConstructMat4:
    1813           0 :             outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
    1814           0 :             break;
    1815             :         case EOpConstructStruct:
    1816             :         {
    1817           0 :             if (node->getType().isArray())
    1818             :             {
    1819           0 :                 UNIMPLEMENTED();
    1820             :             }
    1821           0 :             const TString &structName = StructNameString(*node->getType().getStruct());
    1822           0 :             mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
    1823           0 :             outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
    1824             :         }
    1825           0 :         break;
    1826             :         case EOpLessThan:
    1827           0 :             outputTriplet(out, visit, "(", " < ", ")");
    1828           0 :             break;
    1829             :         case EOpGreaterThan:
    1830           0 :             outputTriplet(out, visit, "(", " > ", ")");
    1831           0 :             break;
    1832             :         case EOpLessThanEqual:
    1833           0 :             outputTriplet(out, visit, "(", " <= ", ")");
    1834           0 :             break;
    1835             :         case EOpGreaterThanEqual:
    1836           0 :             outputTriplet(out, visit, "(", " >= ", ")");
    1837           0 :             break;
    1838             :         case EOpVectorEqual:
    1839           0 :             outputTriplet(out, visit, "(", " == ", ")");
    1840           0 :             break;
    1841             :         case EOpVectorNotEqual:
    1842           0 :             outputTriplet(out, visit, "(", " != ", ")");
    1843           0 :             break;
    1844             :         case EOpMod:
    1845           0 :             ASSERT(node->getUseEmulatedFunction());
    1846           0 :             writeEmulatedFunctionTriplet(out, visit, "mod(");
    1847           0 :             break;
    1848             :         case EOpModf:
    1849           0 :             outputTriplet(out, visit, "modf(", ", ", ")");
    1850           0 :             break;
    1851             :         case EOpPow:
    1852           0 :             outputTriplet(out, visit, "pow(", ", ", ")");
    1853           0 :             break;
    1854             :         case EOpAtan:
    1855           0 :             ASSERT(node->getSequence()->size() == 2);  // atan(x) is a unary operator
    1856           0 :             ASSERT(node->getUseEmulatedFunction());
    1857           0 :             writeEmulatedFunctionTriplet(out, visit, "atan(");
    1858           0 :             break;
    1859             :         case EOpMin:
    1860           0 :             outputTriplet(out, visit, "min(", ", ", ")");
    1861           0 :             break;
    1862             :         case EOpMax:
    1863           0 :             outputTriplet(out, visit, "max(", ", ", ")");
    1864           0 :             break;
    1865             :         case EOpClamp:
    1866           0 :             outputTriplet(out, visit, "clamp(", ", ", ")");
    1867           0 :             break;
    1868             :         case EOpMix:
    1869             :         {
    1870           0 :             TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
    1871           0 :             if (lastParamNode->getType().getBasicType() == EbtBool)
    1872             :             {
    1873             :                 // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
    1874             :                 // so use emulated version.
    1875           0 :                 ASSERT(node->getUseEmulatedFunction());
    1876           0 :                 writeEmulatedFunctionTriplet(out, visit, "mix(");
    1877             :             }
    1878             :             else
    1879             :             {
    1880           0 :                 outputTriplet(out, visit, "lerp(", ", ", ")");
    1881             :             }
    1882           0 :             break;
    1883             :         }
    1884             :         case EOpStep:
    1885           0 :             outputTriplet(out, visit, "step(", ", ", ")");
    1886           0 :             break;
    1887             :         case EOpSmoothStep:
    1888           0 :             outputTriplet(out, visit, "smoothstep(", ", ", ")");
    1889           0 :             break;
    1890             :         case EOpDistance:
    1891           0 :             outputTriplet(out, visit, "distance(", ", ", ")");
    1892           0 :             break;
    1893             :         case EOpDot:
    1894           0 :             outputTriplet(out, visit, "dot(", ", ", ")");
    1895           0 :             break;
    1896             :         case EOpCross:
    1897           0 :             outputTriplet(out, visit, "cross(", ", ", ")");
    1898           0 :             break;
    1899             :         case EOpFaceForward:
    1900           0 :             ASSERT(node->getUseEmulatedFunction());
    1901           0 :             writeEmulatedFunctionTriplet(out, visit, "faceforward(");
    1902           0 :             break;
    1903             :         case EOpReflect:
    1904           0 :             outputTriplet(out, visit, "reflect(", ", ", ")");
    1905           0 :             break;
    1906             :         case EOpRefract:
    1907           0 :             outputTriplet(out, visit, "refract(", ", ", ")");
    1908           0 :             break;
    1909             :         case EOpOuterProduct:
    1910           0 :             ASSERT(node->getUseEmulatedFunction());
    1911           0 :             writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
    1912           0 :             break;
    1913             :         case EOpMul:
    1914           0 :             outputTriplet(out, visit, "(", " * ", ")");
    1915           0 :             break;
    1916             :         default:
    1917           0 :             UNREACHABLE();
    1918             :     }
    1919             : 
    1920           0 :     return true;
    1921             : }
    1922             : 
    1923           0 : void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node)
    1924             : {
    1925           0 :     out << "if (";
    1926             : 
    1927           0 :     node->getCondition()->traverse(this);
    1928             : 
    1929           0 :     out << ")\n";
    1930             : 
    1931           0 :     outputLineDirective(out, node->getLine().first_line);
    1932             : 
    1933           0 :     bool discard = false;
    1934             : 
    1935           0 :     if (node->getTrueBlock())
    1936             :     {
    1937             :         // The trueBlock child node will output braces.
    1938           0 :         node->getTrueBlock()->traverse(this);
    1939             : 
    1940             :         // Detect true discard
    1941           0 :         discard = (discard || FindDiscard::search(node->getTrueBlock()));
    1942             :     }
    1943             :     else
    1944             :     {
    1945             :         // TODO(oetuaho): Check if the semicolon inside is necessary.
    1946             :         // It's there as a result of conservative refactoring of the output.
    1947           0 :         out << "{;}\n";
    1948             :     }
    1949             : 
    1950           0 :     outputLineDirective(out, node->getLine().first_line);
    1951             : 
    1952           0 :     if (node->getFalseBlock())
    1953             :     {
    1954           0 :         out << "else\n";
    1955             : 
    1956           0 :         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
    1957             : 
    1958             :         // The falseBlock child node will output braces.
    1959           0 :         node->getFalseBlock()->traverse(this);
    1960             : 
    1961           0 :         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
    1962             : 
    1963             :         // Detect false discard
    1964           0 :         discard = (discard || FindDiscard::search(node->getFalseBlock()));
    1965             :     }
    1966             : 
    1967             :     // ANGLE issue 486: Detect problematic conditional discard
    1968           0 :     if (discard)
    1969             :     {
    1970           0 :         mUsesDiscardRewriting = true;
    1971             :     }
    1972           0 : }
    1973             : 
    1974           0 : bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
    1975             : {
    1976             :     // Ternary ops should have been already converted to something else in the AST. HLSL ternary
    1977             :     // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
    1978           0 :     UNREACHABLE();
    1979             :     return false;
    1980             : }
    1981             : 
    1982           0 : bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node)
    1983             : {
    1984           0 :     TInfoSinkBase &out = getInfoSink();
    1985             : 
    1986           0 :     ASSERT(mInsideFunction);
    1987             : 
    1988             :     // D3D errors when there is a gradient operation in a loop in an unflattened if.
    1989           0 :     if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
    1990             :     {
    1991           0 :         out << "FLATTEN ";
    1992             :     }
    1993             : 
    1994           0 :     writeIfElse(out, node);
    1995             : 
    1996           0 :     return false;
    1997             : }
    1998             : 
    1999           0 : bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
    2000             : {
    2001           0 :     TInfoSinkBase &out = getInfoSink();
    2002             : 
    2003           0 :     if (node->getStatementList())
    2004             :     {
    2005           0 :         node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
    2006           0 :         outputTriplet(out, visit, "switch (", ") ", "");
    2007             :         // The curly braces get written when visiting the statementList aggregate
    2008             :     }
    2009             :     else
    2010             :     {
    2011             :         // No statementList, so it won't output curly braces
    2012           0 :         outputTriplet(out, visit, "switch (", ") {", "}\n");
    2013             :     }
    2014           0 :     return true;
    2015             : }
    2016             : 
    2017           0 : bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
    2018             : {
    2019           0 :     TInfoSinkBase &out = getInfoSink();
    2020             : 
    2021           0 :     if (node->hasCondition())
    2022             :     {
    2023           0 :         outputTriplet(out, visit, "case (", "", "):\n");
    2024           0 :         return true;
    2025             :     }
    2026             :     else
    2027             :     {
    2028           0 :         out << "default:\n";
    2029           0 :         return false;
    2030             :     }
    2031             : }
    2032             : 
    2033           0 : void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
    2034             : {
    2035           0 :     TInfoSinkBase &out = getInfoSink();
    2036           0 :     writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
    2037           0 : }
    2038             : 
    2039           0 : bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
    2040             : {
    2041           0 :     mNestedLoopDepth++;
    2042             : 
    2043           0 :     bool wasDiscontinuous = mInsideDiscontinuousLoop;
    2044           0 :     mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
    2045           0 :     mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
    2046             : 
    2047           0 :     TInfoSinkBase &out = getInfoSink();
    2048             : 
    2049           0 :     if (mOutputType == SH_HLSL_3_0_OUTPUT)
    2050             :     {
    2051           0 :         if (handleExcessiveLoop(out, node))
    2052             :         {
    2053           0 :             mInsideDiscontinuousLoop = wasDiscontinuous;
    2054           0 :             mNestedLoopDepth--;
    2055             : 
    2056           0 :             return false;
    2057             :         }
    2058             :     }
    2059             : 
    2060           0 :     const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
    2061           0 :     if (node->getType() == ELoopDoWhile)
    2062             :     {
    2063           0 :         out << "{" << unroll << " do\n";
    2064             : 
    2065           0 :         outputLineDirective(out, node->getLine().first_line);
    2066             :     }
    2067             :     else
    2068             :     {
    2069           0 :         out << "{" << unroll << " for(";
    2070             : 
    2071           0 :         if (node->getInit())
    2072             :         {
    2073           0 :             node->getInit()->traverse(this);
    2074             :         }
    2075             : 
    2076           0 :         out << "; ";
    2077             : 
    2078           0 :         if (node->getCondition())
    2079             :         {
    2080           0 :             node->getCondition()->traverse(this);
    2081             :         }
    2082             : 
    2083           0 :         out << "; ";
    2084             : 
    2085           0 :         if (node->getExpression())
    2086             :         {
    2087           0 :             node->getExpression()->traverse(this);
    2088             :         }
    2089             : 
    2090           0 :         out << ")\n";
    2091             : 
    2092           0 :         outputLineDirective(out, node->getLine().first_line);
    2093             :     }
    2094             : 
    2095           0 :     if (node->getBody())
    2096             :     {
    2097             :         // The loop body node will output braces.
    2098           0 :         node->getBody()->traverse(this);
    2099             :     }
    2100             :     else
    2101             :     {
    2102             :         // TODO(oetuaho): Check if the semicolon inside is necessary.
    2103             :         // It's there as a result of conservative refactoring of the output.
    2104           0 :         out << "{;}\n";
    2105             :     }
    2106             : 
    2107           0 :     outputLineDirective(out, node->getLine().first_line);
    2108             : 
    2109           0 :     if (node->getType() == ELoopDoWhile)
    2110             :     {
    2111           0 :         outputLineDirective(out, node->getCondition()->getLine().first_line);
    2112           0 :         out << "while(\n";
    2113             : 
    2114           0 :         node->getCondition()->traverse(this);
    2115             : 
    2116           0 :         out << ");";
    2117             :     }
    2118             : 
    2119           0 :     out << "}\n";
    2120             : 
    2121           0 :     mInsideDiscontinuousLoop = wasDiscontinuous;
    2122           0 :     mNestedLoopDepth--;
    2123             : 
    2124           0 :     return false;
    2125             : }
    2126             : 
    2127           0 : bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
    2128             : {
    2129           0 :     TInfoSinkBase &out = getInfoSink();
    2130             : 
    2131           0 :     switch (node->getFlowOp())
    2132             :     {
    2133             :       case EOpKill:
    2134           0 :           outputTriplet(out, visit, "discard;\n", "", "");
    2135           0 :         break;
    2136             :       case EOpBreak:
    2137           0 :         if (visit == PreVisit)
    2138             :         {
    2139           0 :             if (mNestedLoopDepth > 1)
    2140             :             {
    2141           0 :                 mUsesNestedBreak = true;
    2142             :             }
    2143             : 
    2144           0 :             if (mExcessiveLoopIndex)
    2145             :             {
    2146           0 :                 out << "{Break";
    2147           0 :                 mExcessiveLoopIndex->traverse(this);
    2148           0 :                 out << " = true; break;}\n";
    2149             :             }
    2150             :             else
    2151             :             {
    2152           0 :                 out << "break;\n";
    2153             :             }
    2154             :         }
    2155           0 :         break;
    2156             :       case EOpContinue:
    2157           0 :           outputTriplet(out, visit, "continue;\n", "", "");
    2158           0 :           break;
    2159             :       case EOpReturn:
    2160           0 :         if (visit == PreVisit)
    2161             :         {
    2162           0 :             if (node->getExpression())
    2163             :             {
    2164           0 :                 out << "return ";
    2165             :             }
    2166             :             else
    2167             :             {
    2168           0 :                 out << "return;\n";
    2169             :             }
    2170             :         }
    2171           0 :         else if (visit == PostVisit)
    2172             :         {
    2173           0 :             if (node->getExpression())
    2174             :             {
    2175           0 :                 out << ";\n";
    2176             :             }
    2177             :         }
    2178           0 :         break;
    2179           0 :       default: UNREACHABLE();
    2180             :     }
    2181             : 
    2182           0 :     return true;
    2183             : }
    2184             : 
    2185             : // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
    2186             : // (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
    2187           0 : bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
    2188             : {
    2189           0 :     const int MAX_LOOP_ITERATIONS = 254;
    2190             : 
    2191             :     // Parse loops of the form:
    2192             :     // for(int index = initial; index [comparator] limit; index += increment)
    2193           0 :     TIntermSymbol *index = NULL;
    2194           0 :     TOperator comparator = EOpNull;
    2195           0 :     int initial = 0;
    2196           0 :     int limit = 0;
    2197           0 :     int increment = 0;
    2198             : 
    2199             :     // Parse index name and intial value
    2200           0 :     if (node->getInit())
    2201             :     {
    2202           0 :         TIntermDeclaration *init = node->getInit()->getAsDeclarationNode();
    2203             : 
    2204           0 :         if (init)
    2205             :         {
    2206           0 :             TIntermSequence *sequence = init->getSequence();
    2207           0 :             TIntermTyped *variable = (*sequence)[0]->getAsTyped();
    2208             : 
    2209           0 :             if (variable && variable->getQualifier() == EvqTemporary)
    2210             :             {
    2211           0 :                 TIntermBinary *assign = variable->getAsBinaryNode();
    2212             : 
    2213           0 :                 if (assign->getOp() == EOpInitialize)
    2214             :                 {
    2215           0 :                     TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
    2216           0 :                     TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
    2217             : 
    2218           0 :                     if (symbol && constant)
    2219             :                     {
    2220           0 :                         if (constant->getBasicType() == EbtInt && constant->isScalar())
    2221             :                         {
    2222           0 :                             index = symbol;
    2223           0 :                             initial = constant->getIConst(0);
    2224             :                         }
    2225             :                     }
    2226             :                 }
    2227             :             }
    2228             :         }
    2229             :     }
    2230             : 
    2231             :     // Parse comparator and limit value
    2232           0 :     if (index != NULL && node->getCondition())
    2233             :     {
    2234           0 :         TIntermBinary *test = node->getCondition()->getAsBinaryNode();
    2235             : 
    2236           0 :         if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
    2237             :         {
    2238           0 :             TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
    2239             : 
    2240           0 :             if (constant)
    2241             :             {
    2242           0 :                 if (constant->getBasicType() == EbtInt && constant->isScalar())
    2243             :                 {
    2244           0 :                     comparator = test->getOp();
    2245           0 :                     limit = constant->getIConst(0);
    2246             :                 }
    2247             :             }
    2248             :         }
    2249             :     }
    2250             : 
    2251             :     // Parse increment
    2252           0 :     if (index != NULL && comparator != EOpNull && node->getExpression())
    2253             :     {
    2254           0 :         TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
    2255           0 :         TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
    2256             : 
    2257           0 :         if (binaryTerminal)
    2258             :         {
    2259           0 :             TOperator op = binaryTerminal->getOp();
    2260           0 :             TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
    2261             : 
    2262           0 :             if (constant)
    2263             :             {
    2264           0 :                 if (constant->getBasicType() == EbtInt && constant->isScalar())
    2265             :                 {
    2266           0 :                     int value = constant->getIConst(0);
    2267             : 
    2268           0 :                     switch (op)
    2269             :                     {
    2270           0 :                       case EOpAddAssign: increment = value;  break;
    2271           0 :                       case EOpSubAssign: increment = -value; break;
    2272           0 :                       default: UNIMPLEMENTED();
    2273             :                     }
    2274             :                 }
    2275             :             }
    2276             :         }
    2277           0 :         else if (unaryTerminal)
    2278             :         {
    2279           0 :             TOperator op = unaryTerminal->getOp();
    2280             : 
    2281           0 :             switch (op)
    2282             :             {
    2283           0 :               case EOpPostIncrement: increment = 1;  break;
    2284           0 :               case EOpPostDecrement: increment = -1; break;
    2285           0 :               case EOpPreIncrement:  increment = 1;  break;
    2286           0 :               case EOpPreDecrement:  increment = -1; break;
    2287           0 :               default: UNIMPLEMENTED();
    2288             :             }
    2289             :         }
    2290             :     }
    2291             : 
    2292           0 :     if (index != NULL && comparator != EOpNull && increment != 0)
    2293             :     {
    2294           0 :         if (comparator == EOpLessThanEqual)
    2295             :         {
    2296           0 :             comparator = EOpLessThan;
    2297           0 :             limit += 1;
    2298             :         }
    2299             : 
    2300           0 :         if (comparator == EOpLessThan)
    2301             :         {
    2302           0 :             int iterations = (limit - initial) / increment;
    2303             : 
    2304           0 :             if (iterations <= MAX_LOOP_ITERATIONS)
    2305             :             {
    2306           0 :                 return false;   // Not an excessive loop
    2307             :             }
    2308             : 
    2309           0 :             TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
    2310           0 :             mExcessiveLoopIndex = index;
    2311             : 
    2312           0 :             out << "{int ";
    2313           0 :             index->traverse(this);
    2314             :             out << ";\n"
    2315           0 :                    "bool Break";
    2316           0 :             index->traverse(this);
    2317           0 :             out << " = false;\n";
    2318             : 
    2319           0 :             bool firstLoopFragment = true;
    2320             : 
    2321           0 :             while (iterations > 0)
    2322             :             {
    2323           0 :                 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
    2324             : 
    2325           0 :                 if (!firstLoopFragment)
    2326             :                 {
    2327           0 :                     out << "if (!Break";
    2328           0 :                     index->traverse(this);
    2329           0 :                     out << ") {\n";
    2330             :                 }
    2331             : 
    2332           0 :                 if (iterations <= MAX_LOOP_ITERATIONS)   // Last loop fragment
    2333             :                 {
    2334           0 :                     mExcessiveLoopIndex = NULL;   // Stops setting the Break flag
    2335             :                 }
    2336             : 
    2337             :                 // for(int index = initial; index < clampedLimit; index += increment)
    2338           0 :                 const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
    2339             : 
    2340           0 :                 out << unroll << " for(";
    2341           0 :                 index->traverse(this);
    2342           0 :                 out << " = ";
    2343           0 :                 out << initial;
    2344             : 
    2345           0 :                 out << "; ";
    2346           0 :                 index->traverse(this);
    2347           0 :                 out << " < ";
    2348           0 :                 out << clampedLimit;
    2349             : 
    2350           0 :                 out << "; ";
    2351           0 :                 index->traverse(this);
    2352           0 :                 out << " += ";
    2353           0 :                 out << increment;
    2354           0 :                 out << ")\n";
    2355             : 
    2356           0 :                 outputLineDirective(out, node->getLine().first_line);
    2357           0 :                 out << "{\n";
    2358             : 
    2359           0 :                 if (node->getBody())
    2360             :                 {
    2361           0 :                     node->getBody()->traverse(this);
    2362             :                 }
    2363             : 
    2364           0 :                 outputLineDirective(out, node->getLine().first_line);
    2365           0 :                 out << ";}\n";
    2366             : 
    2367           0 :                 if (!firstLoopFragment)
    2368             :                 {
    2369           0 :                     out << "}\n";
    2370             :                 }
    2371             : 
    2372           0 :                 firstLoopFragment = false;
    2373             : 
    2374           0 :                 initial += MAX_LOOP_ITERATIONS * increment;
    2375           0 :                 iterations -= MAX_LOOP_ITERATIONS;
    2376             :             }
    2377             : 
    2378           0 :             out << "}";
    2379             : 
    2380           0 :             mExcessiveLoopIndex = restoreIndex;
    2381             : 
    2382           0 :             return true;
    2383             :         }
    2384           0 :         else UNIMPLEMENTED();
    2385             :     }
    2386             : 
    2387           0 :     return false;   // Not handled as an excessive loop
    2388             : }
    2389             : 
    2390           0 : void OutputHLSL::outputTriplet(TInfoSinkBase &out,
    2391             :                                Visit visit,
    2392             :                                const char *preString,
    2393             :                                const char *inString,
    2394             :                                const char *postString)
    2395             : {
    2396           0 :     if (visit == PreVisit)
    2397             :     {
    2398           0 :         out << preString;
    2399             :     }
    2400           0 :     else if (visit == InVisit)
    2401             :     {
    2402           0 :         out << inString;
    2403             :     }
    2404           0 :     else if (visit == PostVisit)
    2405             :     {
    2406           0 :         out << postString;
    2407             :     }
    2408           0 : }
    2409             : 
    2410           0 : void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
    2411             : {
    2412           0 :     if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
    2413             :     {
    2414           0 :         out << "\n";
    2415           0 :         out << "#line " << line;
    2416             : 
    2417           0 :         if (mSourcePath)
    2418             :         {
    2419           0 :             out << " \"" << mSourcePath << "\"";
    2420             :         }
    2421             : 
    2422           0 :         out << "\n";
    2423             :     }
    2424           0 : }
    2425             : 
    2426           0 : TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
    2427             : {
    2428           0 :     TQualifier qualifier = symbol->getQualifier();
    2429           0 :     const TType &type    = symbol->getType();
    2430           0 :     const TName &name    = symbol->getName();
    2431           0 :     TString nameStr;
    2432             : 
    2433           0 :     if (name.getString().empty())  // HLSL demands named arguments, also for prototypes
    2434             :     {
    2435           0 :         nameStr = "x" + str(mUniqueIndex++);
    2436             :     }
    2437             :     else
    2438             :     {
    2439           0 :         nameStr = DecorateIfNeeded(name);
    2440             :     }
    2441             : 
    2442           0 :     if (IsSampler(type.getBasicType()))
    2443             :     {
    2444           0 :         if (mOutputType == SH_HLSL_4_1_OUTPUT)
    2445             :         {
    2446             :             // Samplers are passed as indices to the sampler array.
    2447           0 :             ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
    2448           0 :             return "const uint " + nameStr + ArrayString(type);
    2449             :         }
    2450           0 :         if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    2451             :         {
    2452           0 :             return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
    2453           0 :                    " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
    2454           0 :                    " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
    2455           0 :                    ArrayString(type);
    2456             :         }
    2457             :     }
    2458             : 
    2459           0 :     TStringStream argString;
    2460           0 :     argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
    2461           0 :               << ArrayString(type);
    2462             : 
    2463             :     // If the structure parameter contains samplers, they need to be passed into the function as
    2464             :     // separate parameters. HLSL doesn't natively support samplers in structs.
    2465           0 :     if (type.isStructureContainingSamplers())
    2466             :     {
    2467           0 :         ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
    2468           0 :         TVector<TIntermSymbol *> samplerSymbols;
    2469           0 :         type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr);
    2470           0 :         for (const TIntermSymbol *sampler : samplerSymbols)
    2471             :         {
    2472           0 :             if (mOutputType == SH_HLSL_4_1_OUTPUT)
    2473             :             {
    2474           0 :                 argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
    2475             :             }
    2476           0 :             else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    2477             :             {
    2478           0 :                 const TType &samplerType = sampler->getType();
    2479           0 :                 ASSERT((!type.isArray() && !samplerType.isArray()) ||
    2480             :                        type.getArraySize() == samplerType.getArraySize());
    2481           0 :                 ASSERT(IsSampler(samplerType.getBasicType()));
    2482           0 :                 argString << ", " << QualifierString(qualifier) << " "
    2483           0 :                           << TextureString(samplerType.getBasicType()) << " texture_"
    2484           0 :                           << sampler->getSymbol() << ArrayString(type) << ", "
    2485           0 :                           << QualifierString(qualifier) << " "
    2486           0 :                           << SamplerString(samplerType.getBasicType()) << " sampler_"
    2487           0 :                           << sampler->getSymbol() << ArrayString(type);
    2488             :             }
    2489             :             else
    2490             :             {
    2491           0 :                 const TType &samplerType = sampler->getType();
    2492           0 :                 ASSERT((!type.isArray() && !samplerType.isArray()) ||
    2493             :                        type.getArraySize() == samplerType.getArraySize());
    2494           0 :                 ASSERT(IsSampler(samplerType.getBasicType()));
    2495           0 :                 argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
    2496           0 :                           << " " << sampler->getSymbol() << ArrayString(type);
    2497             :             }
    2498             :         }
    2499             :     }
    2500             : 
    2501           0 :     return argString.str();
    2502             : }
    2503             : 
    2504           0 : TString OutputHLSL::initializer(const TType &type)
    2505             : {
    2506           0 :     TString string;
    2507             : 
    2508           0 :     size_t size = type.getObjectSize();
    2509           0 :     for (size_t component = 0; component < size; component++)
    2510             :     {
    2511           0 :         string += "0";
    2512             : 
    2513           0 :         if (component + 1 < size)
    2514             :         {
    2515           0 :             string += ", ";
    2516             :         }
    2517             :     }
    2518             : 
    2519           0 :     return "{" + string + "}";
    2520             : }
    2521             : 
    2522           0 : void OutputHLSL::outputConstructor(TInfoSinkBase &out,
    2523             :                                    Visit visit,
    2524             :                                    const TType &type,
    2525             :                                    const char *name,
    2526             :                                    const TIntermSequence *parameters)
    2527             : {
    2528           0 :     if (type.isArray())
    2529             :     {
    2530           0 :         UNIMPLEMENTED();
    2531             :     }
    2532             : 
    2533           0 :     if (visit == PreVisit)
    2534             :     {
    2535           0 :         TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
    2536             : 
    2537           0 :         out << constructorName << "(";
    2538             :     }
    2539           0 :     else if (visit == InVisit)
    2540             :     {
    2541           0 :         out << ", ";
    2542             :     }
    2543           0 :     else if (visit == PostVisit)
    2544             :     {
    2545           0 :         out << ")";
    2546             :     }
    2547           0 : }
    2548             : 
    2549           0 : const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
    2550             :                                                      const TType &type,
    2551             :                                                      const TConstantUnion *const constUnion)
    2552             : {
    2553           0 :     const TConstantUnion *constUnionIterated = constUnion;
    2554             : 
    2555           0 :     const TStructure* structure = type.getStruct();
    2556           0 :     if (structure)
    2557             :     {
    2558           0 :         out << StructNameString(*structure) + "_ctor(";
    2559             : 
    2560           0 :         const TFieldList& fields = structure->fields();
    2561             : 
    2562           0 :         for (size_t i = 0; i < fields.size(); i++)
    2563             :         {
    2564           0 :             const TType *fieldType = fields[i]->type();
    2565           0 :             constUnionIterated     = writeConstantUnion(out, *fieldType, constUnionIterated);
    2566             : 
    2567           0 :             if (i != fields.size() - 1)
    2568             :             {
    2569           0 :                 out << ", ";
    2570             :             }
    2571             :         }
    2572             : 
    2573           0 :         out << ")";
    2574             :     }
    2575             :     else
    2576             :     {
    2577           0 :         size_t size = type.getObjectSize();
    2578           0 :         bool writeType = size > 1;
    2579             : 
    2580           0 :         if (writeType)
    2581             :         {
    2582           0 :             out << TypeString(type) << "(";
    2583             :         }
    2584           0 :         constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size);
    2585           0 :         if (writeType)
    2586             :         {
    2587           0 :             out << ")";
    2588             :         }
    2589             :     }
    2590             : 
    2591           0 :     return constUnionIterated;
    2592             : }
    2593             : 
    2594           0 : void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
    2595             : {
    2596           0 :     TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
    2597           0 :     outputTriplet(out, visit, preString.c_str(), ", ", ")");
    2598           0 : }
    2599             : 
    2600           0 : bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
    2601             : {
    2602           0 :     sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
    2603           0 :     expression->traverse(&searchSymbol);
    2604             : 
    2605           0 :     if (searchSymbol.foundMatch())
    2606             :     {
    2607             :         // Type already printed
    2608           0 :         out << "t" + str(mUniqueIndex) + " = ";
    2609           0 :         expression->traverse(this);
    2610           0 :         out << ", ";
    2611           0 :         symbolNode->traverse(this);
    2612           0 :         out << " = t" + str(mUniqueIndex);
    2613             : 
    2614           0 :         mUniqueIndex++;
    2615           0 :         return true;
    2616             :     }
    2617             : 
    2618           0 :     return false;
    2619             : }
    2620             : 
    2621           0 : bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
    2622             : {
    2623             :     // We support writing constant unions and constructors that only take constant unions as
    2624             :     // parameters as HLSL literals.
    2625           0 :     return expression->getAsConstantUnion() ||
    2626           0 :            expression->isConstructorWithOnlyConstantUnionParameters();
    2627             : }
    2628             : 
    2629           0 : bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
    2630             :                                              TIntermSymbol *symbolNode,
    2631             :                                              TIntermTyped *expression)
    2632             : {
    2633           0 :     if (canWriteAsHLSLLiteral(expression))
    2634             :     {
    2635           0 :         symbolNode->traverse(this);
    2636           0 :         if (expression->getType().isArray())
    2637             :         {
    2638           0 :             out << "[" << expression->getType().getArraySize() << "]";
    2639             :         }
    2640           0 :         out << " = {";
    2641           0 :         if (expression->getAsConstantUnion())
    2642             :         {
    2643           0 :             TIntermConstantUnion *nodeConst  = expression->getAsConstantUnion();
    2644           0 :             const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
    2645           0 :             writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
    2646             :         }
    2647             :         else
    2648             :         {
    2649           0 :             TIntermAggregate *constructor = expression->getAsAggregate();
    2650           0 :             ASSERT(constructor != nullptr);
    2651           0 :             for (TIntermNode *&node : *constructor->getSequence())
    2652             :             {
    2653           0 :                 TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
    2654           0 :                 ASSERT(nodeConst);
    2655           0 :                 const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
    2656           0 :                 writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
    2657           0 :                 if (node != constructor->getSequence()->back())
    2658             :                 {
    2659           0 :                     out << ", ";
    2660             :                 }
    2661             :             }
    2662             :         }
    2663           0 :         out << "}";
    2664           0 :         return true;
    2665             :     }
    2666           0 :     return false;
    2667             : }
    2668             : 
    2669           0 : TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
    2670             : {
    2671           0 :     const TFieldList &fields = structure.fields();
    2672             : 
    2673           0 :     for (const auto &eqFunction : mStructEqualityFunctions)
    2674             :     {
    2675           0 :         if (eqFunction->structure == &structure)
    2676             :         {
    2677           0 :             return eqFunction->functionName;
    2678             :         }
    2679             :     }
    2680             : 
    2681           0 :     const TString &structNameString = StructNameString(structure);
    2682             : 
    2683           0 :     StructEqualityFunction *function = new StructEqualityFunction();
    2684           0 :     function->structure = &structure;
    2685           0 :     function->functionName = "angle_eq_" + structNameString;
    2686             : 
    2687           0 :     TInfoSinkBase fnOut;
    2688             : 
    2689           0 :     fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n"
    2690             :           << "{\n"
    2691           0 :              "    return ";
    2692             : 
    2693           0 :     for (size_t i = 0; i < fields.size(); i++)
    2694             :     {
    2695           0 :         const TField *field = fields[i];
    2696           0 :         const TType *fieldType = field->type();
    2697             : 
    2698           0 :         const TString &fieldNameA = "a." + Decorate(field->name());
    2699           0 :         const TString &fieldNameB = "b." + Decorate(field->name());
    2700             : 
    2701           0 :         if (i > 0)
    2702             :         {
    2703           0 :             fnOut << " && ";
    2704             :         }
    2705             : 
    2706           0 :         fnOut << "(";
    2707           0 :         outputEqual(PreVisit, *fieldType, EOpEqual, fnOut);
    2708           0 :         fnOut << fieldNameA;
    2709           0 :         outputEqual(InVisit, *fieldType, EOpEqual, fnOut);
    2710           0 :         fnOut << fieldNameB;
    2711           0 :         outputEqual(PostVisit, *fieldType, EOpEqual, fnOut);
    2712           0 :         fnOut << ")";
    2713             :     }
    2714             : 
    2715           0 :     fnOut << ";\n" << "}\n";
    2716             : 
    2717           0 :     function->functionDefinition = fnOut.c_str();
    2718             : 
    2719           0 :     mStructEqualityFunctions.push_back(function);
    2720           0 :     mEqualityFunctions.push_back(function);
    2721             : 
    2722           0 :     return function->functionName;
    2723             : }
    2724             : 
    2725           0 : TString OutputHLSL::addArrayEqualityFunction(const TType& type)
    2726             : {
    2727           0 :     for (const auto &eqFunction : mArrayEqualityFunctions)
    2728             :     {
    2729           0 :         if (eqFunction->type == type)
    2730             :         {
    2731           0 :             return eqFunction->functionName;
    2732             :         }
    2733             :     }
    2734             : 
    2735           0 :     const TString &typeName = TypeString(type);
    2736             : 
    2737           0 :     ArrayHelperFunction *function = new ArrayHelperFunction();
    2738           0 :     function->type = type;
    2739             : 
    2740           0 :     TInfoSinkBase fnNameOut;
    2741           0 :     fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
    2742           0 :     function->functionName = fnNameOut.c_str();
    2743             : 
    2744           0 :     TType nonArrayType = type;
    2745           0 :     nonArrayType.clearArrayness();
    2746             : 
    2747           0 :     TInfoSinkBase fnOut;
    2748             : 
    2749           0 :     fnOut << "bool " << function->functionName << "("
    2750           0 :           << typeName << " a[" << type.getArraySize() << "], "
    2751           0 :           << typeName << " b[" << type.getArraySize() << "])\n"
    2752             :           << "{\n"
    2753           0 :              "    for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
    2754             :              "    {\n"
    2755           0 :              "        if (";
    2756             : 
    2757           0 :     outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut);
    2758           0 :     fnOut << "a[i]";
    2759           0 :     outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut);
    2760           0 :     fnOut << "b[i]";
    2761           0 :     outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut);
    2762             : 
    2763             :     fnOut << ") { return false; }\n"
    2764             :              "    }\n"
    2765             :              "    return true;\n"
    2766           0 :              "}\n";
    2767             : 
    2768           0 :     function->functionDefinition = fnOut.c_str();
    2769             : 
    2770           0 :     mArrayEqualityFunctions.push_back(function);
    2771           0 :     mEqualityFunctions.push_back(function);
    2772             : 
    2773           0 :     return function->functionName;
    2774             : }
    2775             : 
    2776           0 : TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
    2777             : {
    2778           0 :     for (const auto &assignFunction : mArrayAssignmentFunctions)
    2779             :     {
    2780           0 :         if (assignFunction.type == type)
    2781             :         {
    2782           0 :             return assignFunction.functionName;
    2783             :         }
    2784             :     }
    2785             : 
    2786           0 :     const TString &typeName = TypeString(type);
    2787             : 
    2788           0 :     ArrayHelperFunction function;
    2789           0 :     function.type = type;
    2790             : 
    2791           0 :     TInfoSinkBase fnNameOut;
    2792           0 :     fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
    2793           0 :     function.functionName = fnNameOut.c_str();
    2794             : 
    2795           0 :     TInfoSinkBase fnOut;
    2796             : 
    2797           0 :     fnOut << "void " << function.functionName << "(out "
    2798           0 :         << typeName << " a[" << type.getArraySize() << "], "
    2799           0 :         << typeName << " b[" << type.getArraySize() << "])\n"
    2800             :         << "{\n"
    2801           0 :            "    for (int i = 0; i < " << type.getArraySize() << "; ++i)\n"
    2802             :            "    {\n"
    2803             :            "        a[i] = b[i];\n"
    2804             :            "    }\n"
    2805           0 :            "}\n";
    2806             : 
    2807           0 :     function.functionDefinition = fnOut.c_str();
    2808             : 
    2809           0 :     mArrayAssignmentFunctions.push_back(function);
    2810             : 
    2811           0 :     return function.functionName;
    2812             : }
    2813             : 
    2814           0 : TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
    2815             : {
    2816           0 :     for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
    2817             :     {
    2818           0 :         if (constructIntoFunction.type == type)
    2819             :         {
    2820           0 :             return constructIntoFunction.functionName;
    2821             :         }
    2822             :     }
    2823             : 
    2824           0 :     const TString &typeName = TypeString(type);
    2825             : 
    2826           0 :     ArrayHelperFunction function;
    2827           0 :     function.type = type;
    2828             : 
    2829           0 :     TInfoSinkBase fnNameOut;
    2830           0 :     fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
    2831           0 :     function.functionName = fnNameOut.c_str();
    2832             : 
    2833           0 :     TInfoSinkBase fnOut;
    2834             : 
    2835           0 :     fnOut << "void " << function.functionName << "(out "
    2836           0 :           << typeName << " a[" << type.getArraySize() << "]";
    2837           0 :     for (unsigned int i = 0u; i < type.getArraySize(); ++i)
    2838             :     {
    2839           0 :         fnOut << ", " << typeName << " b" << i;
    2840             :     }
    2841             :     fnOut << ")\n"
    2842           0 :              "{\n";
    2843             : 
    2844           0 :     for (unsigned int i = 0u; i < type.getArraySize(); ++i)
    2845             :     {
    2846           0 :         fnOut << "    a[" << i << "] = b" << i << ";\n";
    2847             :     }
    2848           0 :     fnOut << "}\n";
    2849             : 
    2850           0 :     function.functionDefinition = fnOut.c_str();
    2851             : 
    2852           0 :     mArrayConstructIntoFunctions.push_back(function);
    2853             : 
    2854           0 :     return function.functionName;
    2855             : }
    2856             : 
    2857           0 : void OutputHLSL::ensureStructDefined(const TType &type)
    2858             : {
    2859           0 :     TStructure *structure = type.getStruct();
    2860             : 
    2861           0 :     if (structure)
    2862             :     {
    2863           0 :         mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
    2864             :     }
    2865           0 : }
    2866             : 
    2867             : }  // namespace sh

Generated by: LCOV version 1.13