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