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