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