Upstream version 6.35.121.0
[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 void OutputHLSL::visitRaw(TIntermRaw *node)
1115 {
1116     mBody << node->getRawText();
1117 }
1118
1119 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
1120 {
1121     TInfoSinkBase &out = mBody;
1122
1123     switch (node->getOp())
1124     {
1125       case EOpAssign:                  outputTriplet(visit, "(", " = ", ")");           break;
1126       case EOpInitialize:
1127         if (visit == PreVisit)
1128         {
1129             // GLSL allows to write things like "float x = x;" where a new variable x is defined
1130             // and the value of an existing variable x is assigned. HLSL uses C semantics (the
1131             // new variable is created before the assignment is evaluated), so we need to convert
1132             // this to "float t = x, x = t;".
1133
1134             TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
1135             TIntermTyped *expression = node->getRight();
1136
1137             sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
1138             expression->traverse(&searchSymbol);
1139             bool sameSymbol = searchSymbol.foundMatch();
1140
1141             if (sameSymbol)
1142             {
1143                 // Type already printed
1144                 out << "t" + str(mUniqueIndex) + " = ";
1145                 expression->traverse(this);
1146                 out << ", ";
1147                 symbolNode->traverse(this);
1148                 out << " = t" + str(mUniqueIndex);
1149
1150                 mUniqueIndex++;
1151                 return false;
1152             }
1153         }
1154         else if (visit == InVisit)
1155         {
1156             out << " = ";
1157         }
1158         break;
1159       case EOpAddAssign:               outputTriplet(visit, "(", " += ", ")");          break;
1160       case EOpSubAssign:               outputTriplet(visit, "(", " -= ", ")");          break;
1161       case EOpMulAssign:               outputTriplet(visit, "(", " *= ", ")");          break;
1162       case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")");          break;
1163       case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")");          break;
1164       case EOpVectorTimesMatrixAssign:
1165         if (visit == PreVisit)
1166         {
1167             out << "(";
1168         }
1169         else if (visit == InVisit)
1170         {
1171             out << " = mul(";
1172             node->getLeft()->traverse(this);
1173             out << ", transpose(";   
1174         }
1175         else
1176         {
1177             out << ")))";
1178         }
1179         break;
1180       case EOpMatrixTimesMatrixAssign:
1181         if (visit == PreVisit)
1182         {
1183             out << "(";
1184         }
1185         else if (visit == InVisit)
1186         {
1187             out << " = mul(";
1188             node->getLeft()->traverse(this);
1189             out << ", ";   
1190         }
1191         else
1192         {
1193             out << "))";
1194         }
1195         break;
1196       case EOpDivAssign:               outputTriplet(visit, "(", " /= ", ")");          break;
1197       case EOpIndexDirect:             outputTriplet(visit, "", "[", "]");              break;
1198       case EOpIndexIndirect:           outputTriplet(visit, "", "[", "]");              break;
1199       case EOpIndexDirectStruct:
1200         if (visit == InVisit)
1201         {
1202             const TStructure* structure = node->getLeft()->getType().getStruct();
1203             const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
1204             const TField* field = structure->fields()[index->getIConst(0)];
1205             out << "." + decorateField(field->name(), node->getLeft()->getType());
1206
1207             return false;
1208         }
1209         break;
1210       case EOpVectorSwizzle:
1211         if (visit == InVisit)
1212         {
1213             out << ".";
1214
1215             TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
1216
1217             if (swizzle)
1218             {
1219                 TIntermSequence &sequence = swizzle->getSequence();
1220
1221                 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
1222                 {
1223                     TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
1224
1225                     if (element)
1226                     {
1227                         int i = element->getIConst(0);
1228
1229                         switch (i)
1230                         {
1231                         case 0: out << "x"; break;
1232                         case 1: out << "y"; break;
1233                         case 2: out << "z"; break;
1234                         case 3: out << "w"; break;
1235                         default: UNREACHABLE();
1236                         }
1237                     }
1238                     else UNREACHABLE();
1239                 }
1240             }
1241             else UNREACHABLE();
1242
1243             return false;   // Fully processed
1244         }
1245         break;
1246       case EOpAdd:               outputTriplet(visit, "(", " + ", ")"); break;
1247       case EOpSub:               outputTriplet(visit, "(", " - ", ")"); break;
1248       case EOpMul:               outputTriplet(visit, "(", " * ", ")"); break;
1249       case EOpDiv:               outputTriplet(visit, "(", " / ", ")"); break;
1250       case EOpEqual:
1251       case EOpNotEqual:
1252         if (node->getLeft()->isScalar())
1253         {
1254             if (node->getOp() == EOpEqual)
1255             {
1256                 outputTriplet(visit, "(", " == ", ")");
1257             }
1258             else
1259             {
1260                 outputTriplet(visit, "(", " != ", ")");
1261             }
1262         }
1263         else if (node->getLeft()->getBasicType() == EbtStruct)
1264         {
1265             if (node->getOp() == EOpEqual)
1266             {
1267                 out << "(";
1268             }
1269             else
1270             {
1271                 out << "!(";
1272             }
1273
1274             const TFieldList &fields = node->getLeft()->getType().getStruct()->fields();
1275
1276             for (size_t i = 0; i < fields.size(); i++)
1277             {
1278                 const TField *field = fields[i];
1279
1280                 node->getLeft()->traverse(this);
1281                 out << "." + decorateField(field->name(), node->getLeft()->getType()) + " == ";
1282                 node->getRight()->traverse(this);
1283                 out << "." + decorateField(field->name(), node->getLeft()->getType());
1284
1285                 if (i < fields.size() - 1)
1286                 {
1287                     out << " && ";
1288                 }
1289             }
1290
1291             out << ")";
1292
1293             return false;
1294         }
1295         else
1296         {
1297             ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
1298
1299             if (node->getOp() == EOpEqual)
1300             {
1301                 outputTriplet(visit, "all(", " == ", ")");
1302             }
1303             else
1304             {
1305                 outputTriplet(visit, "!all(", " == ", ")");
1306             }
1307         }
1308         break;
1309       case EOpLessThan:          outputTriplet(visit, "(", " < ", ")");   break;
1310       case EOpGreaterThan:       outputTriplet(visit, "(", " > ", ")");   break;
1311       case EOpLessThanEqual:     outputTriplet(visit, "(", " <= ", ")");  break;
1312       case EOpGreaterThanEqual:  outputTriplet(visit, "(", " >= ", ")");  break;
1313       case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")");   break;
1314       case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")");   break;
1315       case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1316       case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
1317       case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
1318       case EOpLogicalOr:
1319         if (node->getRight()->hasSideEffects())
1320         {
1321             out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
1322             return false;
1323         }
1324         else
1325         {
1326            outputTriplet(visit, "(", " || ", ")");
1327            return true;
1328         }
1329       case EOpLogicalXor:
1330         mUsesXor = true;
1331         outputTriplet(visit, "xor(", ", ", ")");
1332         break;
1333       case EOpLogicalAnd:
1334         if (node->getRight()->hasSideEffects())
1335         {
1336             out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
1337             return false;
1338         }
1339         else
1340         {
1341            outputTriplet(visit, "(", " && ", ")");
1342            return true;
1343         }
1344       default: UNREACHABLE();
1345     }
1346
1347     return true;
1348 }
1349
1350 bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1351 {
1352     switch (node->getOp())
1353     {
1354       case EOpNegative:         outputTriplet(visit, "(-", "", ")");  break;
1355       case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")");  break;
1356       case EOpLogicalNot:       outputTriplet(visit, "(!", "", ")");  break;
1357       case EOpPostIncrement:    outputTriplet(visit, "(", "", "++)"); break;
1358       case EOpPostDecrement:    outputTriplet(visit, "(", "", "--)"); break;
1359       case EOpPreIncrement:     outputTriplet(visit, "(++", "", ")"); break;
1360       case EOpPreDecrement:     outputTriplet(visit, "(--", "", ")"); break;
1361       case EOpConvIntToBool:
1362       case EOpConvFloatToBool:
1363         switch (node->getOperand()->getType().getNominalSize())
1364         {
1365           case 1:    outputTriplet(visit, "bool(", "", ")");  break;
1366           case 2:    outputTriplet(visit, "bool2(", "", ")"); break;
1367           case 3:    outputTriplet(visit, "bool3(", "", ")"); break;
1368           case 4:    outputTriplet(visit, "bool4(", "", ")"); break;
1369           default: UNREACHABLE();
1370         }
1371         break;
1372       case EOpConvBoolToFloat:
1373       case EOpConvIntToFloat:
1374         switch (node->getOperand()->getType().getNominalSize())
1375         {
1376           case 1:    outputTriplet(visit, "float(", "", ")");  break;
1377           case 2:    outputTriplet(visit, "float2(", "", ")"); break;
1378           case 3:    outputTriplet(visit, "float3(", "", ")"); break;
1379           case 4:    outputTriplet(visit, "float4(", "", ")"); break;
1380           default: UNREACHABLE();
1381         }
1382         break;
1383       case EOpConvFloatToInt:
1384       case EOpConvBoolToInt:
1385         switch (node->getOperand()->getType().getNominalSize())
1386         {
1387           case 1:    outputTriplet(visit, "int(", "", ")");  break;
1388           case 2:    outputTriplet(visit, "int2(", "", ")"); break;
1389           case 3:    outputTriplet(visit, "int3(", "", ")"); break;
1390           case 4:    outputTriplet(visit, "int4(", "", ")"); break;
1391           default: UNREACHABLE();
1392         }
1393         break;
1394       case EOpRadians:          outputTriplet(visit, "radians(", "", ")");   break;
1395       case EOpDegrees:          outputTriplet(visit, "degrees(", "", ")");   break;
1396       case EOpSin:              outputTriplet(visit, "sin(", "", ")");       break;
1397       case EOpCos:              outputTriplet(visit, "cos(", "", ")");       break;
1398       case EOpTan:              outputTriplet(visit, "tan(", "", ")");       break;
1399       case EOpAsin:             outputTriplet(visit, "asin(", "", ")");      break;
1400       case EOpAcos:             outputTriplet(visit, "acos(", "", ")");      break;
1401       case EOpAtan:             outputTriplet(visit, "atan(", "", ")");      break;
1402       case EOpExp:              outputTriplet(visit, "exp(", "", ")");       break;
1403       case EOpLog:              outputTriplet(visit, "log(", "", ")");       break;
1404       case EOpExp2:             outputTriplet(visit, "exp2(", "", ")");      break;
1405       case EOpLog2:             outputTriplet(visit, "log2(", "", ")");      break;
1406       case EOpSqrt:             outputTriplet(visit, "sqrt(", "", ")");      break;
1407       case EOpInverseSqrt:      outputTriplet(visit, "rsqrt(", "", ")");     break;
1408       case EOpAbs:              outputTriplet(visit, "abs(", "", ")");       break;
1409       case EOpSign:             outputTriplet(visit, "sign(", "", ")");      break;
1410       case EOpFloor:            outputTriplet(visit, "floor(", "", ")");     break;
1411       case EOpCeil:             outputTriplet(visit, "ceil(", "", ")");      break;
1412       case EOpFract:            outputTriplet(visit, "frac(", "", ")");      break;
1413       case EOpLength:           outputTriplet(visit, "length(", "", ")");    break;
1414       case EOpNormalize:        outputTriplet(visit, "normalize(", "", ")"); break;
1415       case EOpDFdx:
1416         if(mInsideDiscontinuousLoop || mOutputLod0Function)
1417         {
1418             outputTriplet(visit, "(", "", ", 0.0)");
1419         }
1420         else
1421         {
1422             outputTriplet(visit, "ddx(", "", ")");
1423         }
1424         break;
1425       case EOpDFdy:
1426         if(mInsideDiscontinuousLoop || mOutputLod0Function)
1427         {
1428             outputTriplet(visit, "(", "", ", 0.0)");
1429         }
1430         else
1431         {
1432            outputTriplet(visit, "ddy(", "", ")");
1433         }
1434         break;
1435       case EOpFwidth:
1436         if(mInsideDiscontinuousLoop || mOutputLod0Function)
1437         {
1438             outputTriplet(visit, "(", "", ", 0.0)");
1439         }
1440         else
1441         {
1442             outputTriplet(visit, "fwidth(", "", ")");
1443         }
1444         break;
1445       case EOpAny:              outputTriplet(visit, "any(", "", ")");       break;
1446       case EOpAll:              outputTriplet(visit, "all(", "", ")");       break;
1447       default: UNREACHABLE();
1448     }
1449
1450     return true;
1451 }
1452
1453 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1454 {
1455     TInfoSinkBase &out = mBody;
1456
1457     switch (node->getOp())
1458     {
1459       case EOpSequence:
1460         {
1461             if (mInsideFunction)
1462             {
1463                 outputLineDirective(node->getLine().first_line);
1464                 out << "{\n";
1465
1466                 mScopeDepth++;
1467
1468                 if (mScopeBracket.size() < mScopeDepth)
1469                 {
1470                     mScopeBracket.push_back(0);   // New scope level
1471                 }
1472                 else
1473                 {
1474                     mScopeBracket[mScopeDepth - 1]++;   // New scope at existing level
1475                 }
1476             }
1477
1478             for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1479             {
1480                 outputLineDirective((*sit)->getLine().first_line);
1481
1482                 traverseStatements(*sit);
1483
1484                 out << ";\n";
1485             }
1486
1487             if (mInsideFunction)
1488             {
1489                 outputLineDirective(node->getLine().last_line);
1490                 out << "}\n";
1491
1492                 mScopeDepth--;
1493             }
1494
1495             return false;
1496         }
1497       case EOpDeclaration:
1498         if (visit == PreVisit)
1499         {
1500             TIntermSequence &sequence = node->getSequence();
1501             TIntermTyped *variable = sequence[0]->getAsTyped();
1502
1503             if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
1504             {
1505                 if (variable->getType().getStruct())
1506                 {
1507                     addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL);
1508                 }
1509
1510                 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "")   // Variable declaration
1511                 {
1512                     if (!mInsideFunction)
1513                     {
1514                         out << "static ";
1515                     }
1516
1517                     out << typeString(variable->getType()) + " ";
1518
1519                     for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
1520                     {
1521                         TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1522
1523                         if (symbol)
1524                         {
1525                             symbol->traverse(this);
1526                             out << arrayString(symbol->getType());
1527                             out << " = " + initializer(symbol->getType());
1528                         }
1529                         else
1530                         {
1531                             (*sit)->traverse(this);
1532                         }
1533
1534                         if (*sit != sequence.back())
1535                         {
1536                             out << ", ";
1537                         }
1538                     }
1539                 }
1540                 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "")   // Type (struct) declaration
1541                 {
1542                     // Already added to constructor map
1543                 }
1544                 else UNREACHABLE();
1545             }
1546             else if (variable && (variable->getQualifier() == EvqVaryingOut || variable->getQualifier() == EvqInvariantVaryingOut))
1547             {
1548                 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
1549                 {
1550                     TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1551
1552                     if (symbol)
1553                     {
1554                         // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
1555                         mReferencedVaryings[symbol->getSymbol()] = symbol;
1556                     }
1557                     else
1558                     {
1559                         (*sit)->traverse(this);
1560                     }
1561                 }
1562             }
1563
1564             return false;
1565         }
1566         else if (visit == InVisit)
1567         {
1568             out << ", ";
1569         }
1570         break;
1571       case EOpPrototype:
1572         if (visit == PreVisit)
1573         {
1574             out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
1575
1576             TIntermSequence &arguments = node->getSequence();
1577
1578             for (unsigned int i = 0; i < arguments.size(); i++)
1579             {
1580                 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1581
1582                 if (symbol)
1583                 {
1584                     out << argumentString(symbol);
1585
1586                     if (i < arguments.size() - 1)
1587                     {
1588                         out << ", ";
1589                     }
1590                 }
1591                 else UNREACHABLE();
1592             }
1593
1594             out << ");\n";
1595
1596             // Also prototype the Lod0 variant if needed
1597             if (mContainsLoopDiscontinuity && !mOutputLod0Function)
1598             {
1599                 mOutputLod0Function = true;
1600                 node->traverse(this);
1601                 mOutputLod0Function = false;
1602             }
1603
1604             return false;
1605         }
1606         break;
1607       case EOpComma:            outputTriplet(visit, "(", ", ", ")");                break;
1608       case EOpFunction:
1609         {
1610             TString name = TFunction::unmangleName(node->getName());
1611
1612             out << typeString(node->getType()) << " ";
1613
1614             if (name == "main")
1615             {
1616                 out << "gl_main(";
1617             }
1618             else
1619             {
1620                 out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
1621             }
1622
1623             TIntermSequence &sequence = node->getSequence();
1624             TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1625
1626             for (unsigned int i = 0; i < arguments.size(); i++)
1627             {
1628                 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1629
1630                 if (symbol)
1631                 {
1632                     if (symbol->getType().getStruct())
1633                     {
1634                         addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL);
1635                     }
1636
1637                     out << argumentString(symbol);
1638
1639                     if (i < arguments.size() - 1)
1640                     {
1641                         out << ", ";
1642                     }
1643                 }
1644                 else UNREACHABLE();
1645             }
1646
1647             out << ")\n"
1648                 "{\n";
1649             
1650             if (sequence.size() > 1)
1651             {
1652                 mInsideFunction = true;
1653                 sequence[1]->traverse(this);
1654                 mInsideFunction = false;
1655             }
1656             
1657             out << "}\n";
1658
1659             if (mContainsLoopDiscontinuity && !mOutputLod0Function)
1660             {
1661                 if (name != "main")
1662                 {
1663                     mOutputLod0Function = true;
1664                     node->traverse(this);
1665                     mOutputLod0Function = false;
1666                 }
1667             }
1668
1669             return false;
1670         }
1671         break;
1672       case EOpFunctionCall:
1673         {
1674             TString name = TFunction::unmangleName(node->getName());
1675             bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
1676
1677             if (node->isUserDefined())
1678             {
1679                 out << decorate(name) << (lod0 ? "Lod0(" : "(");
1680             }
1681             else
1682             {
1683                 if (name == "texture2D")
1684                 {
1685                     if (!lod0)
1686                     {
1687                         if (node->getSequence().size() == 2)
1688                         {
1689                             mUsesTexture2D = true;
1690                         }
1691                         else if (node->getSequence().size() == 3)
1692                         {
1693                             mUsesTexture2D_bias = true;
1694                         }
1695                         else UNREACHABLE();
1696
1697                         out << "gl_texture2D(";
1698                     }
1699                     else
1700                     {
1701                         if (node->getSequence().size() == 2)
1702                         {
1703                             mUsesTexture2DLod0 = true;
1704                         }
1705                         else if (node->getSequence().size() == 3)
1706                         {
1707                             mUsesTexture2DLod0_bias = true;
1708                         }
1709                         else UNREACHABLE();
1710
1711                         out << "gl_texture2DLod0(";
1712                     }
1713                 }
1714                 else if (name == "texture2DProj")
1715                 {
1716                     if (!lod0)
1717                     {
1718                         if (node->getSequence().size() == 2)
1719                         {
1720                             mUsesTexture2DProj = true;
1721                         }
1722                         else if (node->getSequence().size() == 3)
1723                         {
1724                             mUsesTexture2DProj_bias = true;
1725                         }
1726                         else UNREACHABLE();
1727
1728                         out << "gl_texture2DProj(";
1729                     }
1730                     else
1731                     {
1732                         if (node->getSequence().size() == 2)
1733                         {
1734                             mUsesTexture2DProjLod0 = true;
1735                         }
1736                         else if (node->getSequence().size() == 3)
1737                         {
1738                             mUsesTexture2DProjLod0_bias = true;
1739                         }
1740                         else UNREACHABLE();
1741
1742                         out << "gl_texture2DProjLod0(";
1743                     }
1744                 }
1745                 else if (name == "textureCube")
1746                 {
1747                     if (!lod0)
1748                     {
1749                         if (node->getSequence().size() == 2)
1750                         {
1751                             mUsesTextureCube = true;
1752                         }
1753                         else if (node->getSequence().size() == 3)
1754                         {
1755                             mUsesTextureCube_bias = true;
1756                         }
1757                         else UNREACHABLE();
1758
1759                         out << "gl_textureCube(";
1760                     }
1761                     else
1762                     {
1763                         if (node->getSequence().size() == 2)
1764                         {
1765                             mUsesTextureCubeLod0 = true;
1766                         }
1767                         else if (node->getSequence().size() == 3)
1768                         {
1769                             mUsesTextureCubeLod0_bias = true;
1770                         }
1771                         else UNREACHABLE();
1772
1773                         out << "gl_textureCubeLod0(";
1774                     }
1775                 }
1776                 else if (name == "texture2DLod")
1777                 {
1778                     if (node->getSequence().size() == 3)
1779                     {
1780                         mUsesTexture2DLod = true;
1781                     }
1782                     else UNREACHABLE();
1783
1784                     out << "gl_texture2DLod(";
1785                 }
1786                 else if (name == "texture2DProjLod")
1787                 {
1788                     if (node->getSequence().size() == 3)
1789                     {
1790                         mUsesTexture2DProjLod = true;
1791                     }
1792                     else UNREACHABLE();
1793
1794                     out << "gl_texture2DProjLod(";
1795                 }
1796                 else if (name == "textureCubeLod")
1797                 {
1798                     if (node->getSequence().size() == 3)
1799                     {
1800                         mUsesTextureCubeLod = true;
1801                     }
1802                     else UNREACHABLE();
1803
1804                     out << "gl_textureCubeLod(";
1805                 }
1806                 else UNREACHABLE();
1807             }
1808
1809             TIntermSequence &arguments = node->getSequence();
1810
1811             for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
1812             {
1813                 if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
1814                 {
1815                     out << "texture_";
1816                     (*arg)->traverse(this);
1817                     out << ", sampler_";
1818                 }
1819
1820                 (*arg)->traverse(this);
1821
1822                 if (arg < arguments.end() - 1)
1823                 {
1824                     out << ", ";
1825                 }
1826             }
1827
1828             out << ")";
1829
1830             return false;
1831         }
1832         break;
1833       case EOpParameters:       outputTriplet(visit, "(", ", ", ")\n{\n");             break;
1834       case EOpConstructFloat:
1835         addConstructor(node->getType(), "vec1", &node->getSequence());
1836         outputTriplet(visit, "vec1(", "", ")");
1837         break;
1838       case EOpConstructVec2:
1839         addConstructor(node->getType(), "vec2", &node->getSequence());
1840         outputTriplet(visit, "vec2(", ", ", ")");
1841         break;
1842       case EOpConstructVec3:
1843         addConstructor(node->getType(), "vec3", &node->getSequence());
1844         outputTriplet(visit, "vec3(", ", ", ")");
1845         break;
1846       case EOpConstructVec4:
1847         addConstructor(node->getType(), "vec4", &node->getSequence());
1848         outputTriplet(visit, "vec4(", ", ", ")");
1849         break;
1850       case EOpConstructBool:
1851         addConstructor(node->getType(), "bvec1", &node->getSequence());
1852         outputTriplet(visit, "bvec1(", "", ")");
1853         break;
1854       case EOpConstructBVec2:
1855         addConstructor(node->getType(), "bvec2", &node->getSequence());
1856         outputTriplet(visit, "bvec2(", ", ", ")");
1857         break;
1858       case EOpConstructBVec3:
1859         addConstructor(node->getType(), "bvec3", &node->getSequence());
1860         outputTriplet(visit, "bvec3(", ", ", ")");
1861         break;
1862       case EOpConstructBVec4:
1863         addConstructor(node->getType(), "bvec4", &node->getSequence());
1864         outputTriplet(visit, "bvec4(", ", ", ")");
1865         break;
1866       case EOpConstructInt:
1867         addConstructor(node->getType(), "ivec1", &node->getSequence());
1868         outputTriplet(visit, "ivec1(", "", ")");
1869         break;
1870       case EOpConstructIVec2:
1871         addConstructor(node->getType(), "ivec2", &node->getSequence());
1872         outputTriplet(visit, "ivec2(", ", ", ")");
1873         break;
1874       case EOpConstructIVec3:
1875         addConstructor(node->getType(), "ivec3", &node->getSequence());
1876         outputTriplet(visit, "ivec3(", ", ", ")");
1877         break;
1878       case EOpConstructIVec4:
1879         addConstructor(node->getType(), "ivec4", &node->getSequence());
1880         outputTriplet(visit, "ivec4(", ", ", ")");
1881         break;
1882       case EOpConstructMat2:
1883         addConstructor(node->getType(), "mat2", &node->getSequence());
1884         outputTriplet(visit, "mat2(", ", ", ")");
1885         break;
1886       case EOpConstructMat3:
1887         addConstructor(node->getType(), "mat3", &node->getSequence());
1888         outputTriplet(visit, "mat3(", ", ", ")");
1889         break;
1890       case EOpConstructMat4: 
1891         addConstructor(node->getType(), "mat4", &node->getSequence());
1892         outputTriplet(visit, "mat4(", ", ", ")");
1893         break;
1894       case EOpConstructStruct:
1895         addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence());
1896         outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")");
1897         break;
1898       case EOpLessThan:         outputTriplet(visit, "(", " < ", ")");                 break;
1899       case EOpGreaterThan:      outputTriplet(visit, "(", " > ", ")");                 break;
1900       case EOpLessThanEqual:    outputTriplet(visit, "(", " <= ", ")");                break;
1901       case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")");                break;
1902       case EOpVectorEqual:      outputTriplet(visit, "(", " == ", ")");                break;
1903       case EOpVectorNotEqual:   outputTriplet(visit, "(", " != ", ")");                break;
1904       case EOpMod:
1905         {
1906             // We need to look at the number of components in both arguments
1907             switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
1908                      + node->getSequence()[1]->getAsTyped()->getNominalSize())
1909             {
1910               case 11: mUsesMod1 = true; break;
1911               case 22: mUsesMod2v = true; break;
1912               case 21: mUsesMod2f = true; break;
1913               case 33: mUsesMod3v = true; break;
1914               case 31: mUsesMod3f = true; break;
1915               case 44: mUsesMod4v = true; break;
1916               case 41: mUsesMod4f = true; break;
1917               default: UNREACHABLE();
1918             }
1919
1920             outputTriplet(visit, "mod(", ", ", ")");
1921         }
1922         break;
1923       case EOpPow:              outputTriplet(visit, "pow(", ", ", ")");               break;
1924       case EOpAtan:
1925         ASSERT(node->getSequence().size() == 2);   // atan(x) is a unary operator
1926         switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
1927         {
1928           case 1: mUsesAtan2_1 = true; break;
1929           case 2: mUsesAtan2_2 = true; break;
1930           case 3: mUsesAtan2_3 = true; break;
1931           case 4: mUsesAtan2_4 = true; break;
1932           default: UNREACHABLE();
1933         }
1934         outputTriplet(visit, "atanyx(", ", ", ")");
1935         break;
1936       case EOpMin:           outputTriplet(visit, "min(", ", ", ")");           break;
1937       case EOpMax:           outputTriplet(visit, "max(", ", ", ")");           break;
1938       case EOpClamp:         outputTriplet(visit, "clamp(", ", ", ")");         break;
1939       case EOpMix:           outputTriplet(visit, "lerp(", ", ", ")");          break;
1940       case EOpStep:          outputTriplet(visit, "step(", ", ", ")");          break;
1941       case EOpSmoothStep:    outputTriplet(visit, "smoothstep(", ", ", ")");    break;
1942       case EOpDistance:      outputTriplet(visit, "distance(", ", ", ")");      break;
1943       case EOpDot:           outputTriplet(visit, "dot(", ", ", ")");           break;
1944       case EOpCross:         outputTriplet(visit, "cross(", ", ", ")");         break;
1945       case EOpFaceForward:
1946         {
1947             switch (node->getSequence()[0]->getAsTyped()->getNominalSize())   // Number of components in the first argument
1948             {
1949             case 1: mUsesFaceforward1 = true; break;
1950             case 2: mUsesFaceforward2 = true; break;
1951             case 3: mUsesFaceforward3 = true; break;
1952             case 4: mUsesFaceforward4 = true; break;
1953             default: UNREACHABLE();
1954             }
1955             
1956             outputTriplet(visit, "faceforward(", ", ", ")");
1957         }
1958         break;
1959       case EOpReflect:       outputTriplet(visit, "reflect(", ", ", ")");       break;
1960       case EOpRefract:       outputTriplet(visit, "refract(", ", ", ")");       break;
1961       case EOpMul:           outputTriplet(visit, "(", " * ", ")");             break;
1962       default: UNREACHABLE();
1963     }
1964
1965     return true;
1966 }
1967
1968 bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1969 {
1970     TInfoSinkBase &out = mBody;
1971
1972     if (node->usesTernaryOperator())
1973     {
1974         out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
1975     }
1976     else  // if/else statement
1977     {
1978         mUnfoldShortCircuit->traverse(node->getCondition());
1979
1980         out << "if (";
1981
1982         node->getCondition()->traverse(this);
1983
1984         out << ")\n";
1985         
1986         outputLineDirective(node->getLine().first_line);
1987         out << "{\n";
1988
1989         bool discard = false;
1990
1991         if (node->getTrueBlock())
1992         {
1993             traverseStatements(node->getTrueBlock());
1994
1995             // Detect true discard
1996             discard = (discard || FindDiscard::search(node->getTrueBlock()));
1997         }
1998
1999         outputLineDirective(node->getLine().first_line);
2000         out << ";\n}\n";
2001
2002         if (node->getFalseBlock())
2003         {
2004             out << "else\n";
2005
2006             outputLineDirective(node->getFalseBlock()->getLine().first_line);
2007             out << "{\n";
2008
2009             outputLineDirective(node->getFalseBlock()->getLine().first_line);
2010             traverseStatements(node->getFalseBlock());
2011
2012             outputLineDirective(node->getFalseBlock()->getLine().first_line);
2013             out << ";\n}\n";
2014
2015             // Detect false discard
2016             discard = (discard || FindDiscard::search(node->getFalseBlock()));
2017         }
2018
2019         // ANGLE issue 486: Detect problematic conditional discard
2020         if (discard && FindSideEffectRewriting::search(node))
2021         {
2022             mUsesDiscardRewriting = true;
2023         }
2024     }
2025
2026     return false;
2027 }
2028
2029 void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
2030 {
2031     writeConstantUnion(node->getType(), node->getUnionArrayPointer());
2032 }
2033
2034 bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
2035 {
2036     bool wasDiscontinuous = mInsideDiscontinuousLoop;
2037
2038     if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
2039     {
2040         mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
2041     }
2042
2043     if (mOutputType == SH_HLSL9_OUTPUT)
2044     {
2045         if (handleExcessiveLoop(node))
2046         {
2047             return false;
2048         }
2049     }
2050
2051     TInfoSinkBase &out = mBody;
2052
2053     if (node->getType() == ELoopDoWhile)
2054     {
2055         out << "{do\n";
2056
2057         outputLineDirective(node->getLine().first_line);
2058         out << "{\n";
2059     }
2060     else
2061     {
2062         out << "{for(";
2063         
2064         if (node->getInit())
2065         {
2066             node->getInit()->traverse(this);
2067         }
2068
2069         out << "; ";
2070
2071         if (node->getCondition())
2072         {
2073             node->getCondition()->traverse(this);
2074         }
2075
2076         out << "; ";
2077
2078         if (node->getExpression())
2079         {
2080             node->getExpression()->traverse(this);
2081         }
2082
2083         out << ")\n";
2084         
2085         outputLineDirective(node->getLine().first_line);
2086         out << "{\n";
2087     }
2088
2089     if (node->getBody())
2090     {
2091         traverseStatements(node->getBody());
2092     }
2093
2094     outputLineDirective(node->getLine().first_line);
2095     out << ";}\n";
2096
2097     if (node->getType() == ELoopDoWhile)
2098     {
2099         outputLineDirective(node->getCondition()->getLine().first_line);
2100         out << "while(\n";
2101
2102         node->getCondition()->traverse(this);
2103
2104         out << ");";
2105     }
2106
2107     out << "}\n";
2108
2109     mInsideDiscontinuousLoop = wasDiscontinuous;
2110
2111     return false;
2112 }
2113
2114 bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
2115 {
2116     TInfoSinkBase &out = mBody;
2117
2118     switch (node->getFlowOp())
2119     {
2120       case EOpKill:
2121         outputTriplet(visit, "discard;\n", "", "");
2122         break;
2123       case EOpBreak:
2124         if (visit == PreVisit)
2125         {
2126             if (mExcessiveLoopIndex)
2127             {
2128                 out << "{Break";
2129                 mExcessiveLoopIndex->traverse(this);
2130                 out << " = true; break;}\n";
2131             }
2132             else
2133             {
2134                 out << "break;\n";
2135             }
2136         }
2137         break;
2138       case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
2139       case EOpReturn:
2140         if (visit == PreVisit)
2141         {
2142             if (node->getExpression())
2143             {
2144                 out << "return ";
2145             }
2146             else
2147             {
2148                 out << "return;\n";
2149             }
2150         }
2151         else if (visit == PostVisit)
2152         {
2153             if (node->getExpression())
2154             {
2155                 out << ";\n";
2156             }
2157         }
2158         break;
2159       default: UNREACHABLE();
2160     }
2161
2162     return true;
2163 }
2164
2165 void OutputHLSL::traverseStatements(TIntermNode *node)
2166 {
2167     if (isSingleStatement(node))
2168     {
2169         mUnfoldShortCircuit->traverse(node);
2170     }
2171
2172     node->traverse(this);
2173 }
2174
2175 bool OutputHLSL::isSingleStatement(TIntermNode *node)
2176 {
2177     TIntermAggregate *aggregate = node->getAsAggregate();
2178
2179     if (aggregate)
2180     {
2181         if (aggregate->getOp() == EOpSequence)
2182         {
2183             return false;
2184         }
2185         else
2186         {
2187             for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
2188             {
2189                 if (!isSingleStatement(*sit))
2190                 {
2191                     return false;
2192                 }
2193             }
2194
2195             return true;
2196         }
2197     }
2198
2199     return true;
2200 }
2201
2202 // Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
2203 // (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
2204 bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
2205 {
2206     const int MAX_LOOP_ITERATIONS = 254;
2207     TInfoSinkBase &out = mBody;
2208
2209     // Parse loops of the form:
2210     // for(int index = initial; index [comparator] limit; index += increment)
2211     TIntermSymbol *index = NULL;
2212     TOperator comparator = EOpNull;
2213     int initial = 0;
2214     int limit = 0;
2215     int increment = 0;
2216
2217     // Parse index name and intial value
2218     if (node->getInit())
2219     {
2220         TIntermAggregate *init = node->getInit()->getAsAggregate();
2221
2222         if (init)
2223         {
2224             TIntermSequence &sequence = init->getSequence();
2225             TIntermTyped *variable = sequence[0]->getAsTyped();
2226
2227             if (variable && variable->getQualifier() == EvqTemporary)
2228             {
2229                 TIntermBinary *assign = variable->getAsBinaryNode();
2230
2231                 if (assign->getOp() == EOpInitialize)
2232                 {
2233                     TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
2234                     TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
2235
2236                     if (symbol && constant)
2237                     {
2238                         if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2239                         {
2240                             index = symbol;
2241                             initial = constant->getIConst(0);
2242                         }
2243                     }
2244                 }
2245             }
2246         }
2247     }
2248
2249     // Parse comparator and limit value
2250     if (index != NULL && node->getCondition())
2251     {
2252         TIntermBinary *test = node->getCondition()->getAsBinaryNode();
2253         
2254         if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
2255         {
2256             TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
2257
2258             if (constant)
2259             {
2260                 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2261                 {
2262                     comparator = test->getOp();
2263                     limit = constant->getIConst(0);
2264                 }
2265             }
2266         }
2267     }
2268
2269     // Parse increment
2270     if (index != NULL && comparator != EOpNull && node->getExpression())
2271     {
2272         TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
2273         TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
2274         
2275         if (binaryTerminal)
2276         {
2277             TOperator op = binaryTerminal->getOp();
2278             TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
2279
2280             if (constant)
2281             {
2282                 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
2283                 {
2284                     int value = constant->getIConst(0);
2285
2286                     switch (op)
2287                     {
2288                       case EOpAddAssign: increment = value;  break;
2289                       case EOpSubAssign: increment = -value; break;
2290                       default: UNIMPLEMENTED();
2291                     }
2292                 }
2293             }
2294         }
2295         else if (unaryTerminal)
2296         {
2297             TOperator op = unaryTerminal->getOp();
2298
2299             switch (op)
2300             {
2301               case EOpPostIncrement: increment = 1;  break;
2302               case EOpPostDecrement: increment = -1; break;
2303               case EOpPreIncrement:  increment = 1;  break;
2304               case EOpPreDecrement:  increment = -1; break;
2305               default: UNIMPLEMENTED();
2306             }
2307         }
2308     }
2309
2310     if (index != NULL && comparator != EOpNull && increment != 0)
2311     {
2312         if (comparator == EOpLessThanEqual)
2313         {
2314             comparator = EOpLessThan;
2315             limit += 1;
2316         }
2317
2318         if (comparator == EOpLessThan)
2319         {
2320             int iterations = (limit - initial) / increment;
2321
2322             if (iterations <= MAX_LOOP_ITERATIONS)
2323             {
2324                 return false;   // Not an excessive loop
2325             }
2326
2327             TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
2328             mExcessiveLoopIndex = index;
2329
2330             out << "{int ";
2331             index->traverse(this);
2332             out << ";\n"
2333                    "bool Break";
2334             index->traverse(this);
2335             out << " = false;\n";
2336
2337             bool firstLoopFragment = true;
2338
2339             while (iterations > 0)
2340             {
2341                 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
2342
2343                 if (!firstLoopFragment)
2344                 {
2345                     out << "if (!Break";
2346                     index->traverse(this);
2347                     out << ") {\n";
2348                 }
2349
2350                 if (iterations <= MAX_LOOP_ITERATIONS)   // Last loop fragment
2351                 {
2352                     mExcessiveLoopIndex = NULL;   // Stops setting the Break flag
2353                 }
2354                 
2355                 // for(int index = initial; index < clampedLimit; index += increment)
2356
2357                 out << "for(";
2358                 index->traverse(this);
2359                 out << " = ";
2360                 out << initial;
2361
2362                 out << "; ";
2363                 index->traverse(this);
2364                 out << " < ";
2365                 out << clampedLimit;
2366
2367                 out << "; ";
2368                 index->traverse(this);
2369                 out << " += ";
2370                 out << increment;
2371                 out << ")\n";
2372                 
2373                 outputLineDirective(node->getLine().first_line);
2374                 out << "{\n";
2375
2376                 if (node->getBody())
2377                 {
2378                     node->getBody()->traverse(this);
2379                 }
2380
2381                 outputLineDirective(node->getLine().first_line);
2382                 out << ";}\n";
2383
2384                 if (!firstLoopFragment)
2385                 {
2386                     out << "}\n";
2387                 }
2388
2389                 firstLoopFragment = false;
2390
2391                 initial += MAX_LOOP_ITERATIONS * increment;
2392                 iterations -= MAX_LOOP_ITERATIONS;
2393             }
2394             
2395             out << "}";
2396
2397             mExcessiveLoopIndex = restoreIndex;
2398
2399             return true;
2400         }
2401         else UNIMPLEMENTED();
2402     }
2403
2404     return false;   // Not handled as an excessive loop
2405 }
2406
2407 void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
2408 {
2409     TInfoSinkBase &out = mBody;
2410
2411     if (visit == PreVisit)
2412     {
2413         out << preString;
2414     }
2415     else if (visit == InVisit)
2416     {
2417         out << inString;
2418     }
2419     else if (visit == PostVisit)
2420     {
2421         out << postString;
2422     }
2423 }
2424
2425 void OutputHLSL::outputLineDirective(int line)
2426 {
2427     if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
2428     {
2429         mBody << "\n";
2430         mBody << "#line " << line;
2431
2432         if (mContext.sourcePath)
2433         {
2434             mBody << " \"" << mContext.sourcePath << "\"";
2435         }
2436         
2437         mBody << "\n";
2438     }
2439 }
2440
2441 TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2442 {
2443     TQualifier qualifier = symbol->getQualifier();
2444     const TType &type = symbol->getType();
2445     TString name = symbol->getSymbol();
2446
2447     if (name.empty())   // HLSL demands named arguments, also for prototypes
2448     {
2449         name = "x" + str(mUniqueIndex++);
2450     }
2451     else
2452     {
2453         name = decorate(name);
2454     }
2455
2456     if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
2457     {
2458        return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " +
2459               qualifierString(qualifier) + " SamplerState sampler_" + name + arrayString(type);
2460     }
2461
2462     return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
2463 }
2464
2465 TString OutputHLSL::qualifierString(TQualifier qualifier)
2466 {
2467     switch(qualifier)
2468     {
2469       case EvqIn:            return "in";
2470       case EvqOut:           return "out";
2471       case EvqInOut:         return "inout";
2472       case EvqConstReadOnly: return "const";
2473       default: UNREACHABLE();
2474     }
2475
2476     return "";
2477 }
2478
2479 TString OutputHLSL::typeString(const TType &type)
2480 {
2481     if (type.getBasicType() == EbtStruct)
2482     {
2483         const TString& typeName = type.getStruct()->name();
2484         if (typeName != "")
2485         {
2486             return structLookup(typeName);
2487         }
2488         else   // Nameless structure, define in place
2489         {
2490             const TFieldList &fields = type.getStruct()->fields();
2491
2492             TString string = "struct\n"
2493                              "{\n";
2494
2495             for (unsigned int i = 0; i < fields.size(); i++)
2496             {
2497                 const TField *field = fields[i];
2498
2499                 string += "    " + typeString(*field->type()) + " " + decorate(field->name()) + arrayString(*field->type()) + ";\n";
2500             }
2501
2502             string += "} ";
2503
2504             return string;
2505         }
2506     }
2507     else if (type.isMatrix())
2508     {
2509         switch (type.getNominalSize())
2510         {
2511           case 2: return "float2x2";
2512           case 3: return "float3x3";
2513           case 4: return "float4x4";
2514         }
2515     }
2516     else
2517     {
2518         switch (type.getBasicType())
2519         {
2520           case EbtFloat:
2521             switch (type.getNominalSize())
2522             {
2523               case 1: return "float";
2524               case 2: return "float2";
2525               case 3: return "float3";
2526               case 4: return "float4";
2527             }
2528           case EbtInt:
2529             switch (type.getNominalSize())
2530             {
2531               case 1: return "int";
2532               case 2: return "int2";
2533               case 3: return "int3";
2534               case 4: return "int4";
2535             }
2536           case EbtBool:
2537             switch (type.getNominalSize())
2538             {
2539               case 1: return "bool";
2540               case 2: return "bool2";
2541               case 3: return "bool3";
2542               case 4: return "bool4";
2543             }
2544           case EbtVoid:
2545             return "void";
2546           case EbtSampler2D:
2547             return "sampler2D";
2548           case EbtSamplerCube:
2549             return "samplerCUBE";
2550           case EbtSamplerExternalOES:
2551             return "sampler2D";
2552           default:
2553             break;
2554         }
2555     }
2556
2557     UNREACHABLE();
2558     return "<unknown type>";
2559 }
2560
2561 TString OutputHLSL::textureString(const TType &type)
2562 {
2563     switch (type.getBasicType())
2564     {
2565       case EbtSampler2D:
2566         return "Texture2D";
2567       case EbtSamplerCube:
2568         return "TextureCube";
2569       case EbtSamplerExternalOES:
2570         return "Texture2D";
2571       default:
2572         break;
2573     }
2574
2575     UNREACHABLE();
2576     return "<unknown texture type>";
2577 }
2578
2579 TString OutputHLSL::arrayString(const TType &type)
2580 {
2581     if (!type.isArray())
2582     {
2583         return "";
2584     }
2585
2586     return "[" + str(type.getArraySize()) + "]";
2587 }
2588
2589 TString OutputHLSL::initializer(const TType &type)
2590 {
2591     TString string;
2592
2593     size_t size = type.getObjectSize();
2594     for (size_t component = 0; component < size; component++)
2595     {
2596         string += "0";
2597
2598         if (component + 1 < size)
2599         {
2600             string += ", ";
2601         }
2602     }
2603
2604     return "{" + string + "}";
2605 }
2606
2607 void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
2608 {
2609     if (name == "")
2610     {
2611         return;   // Nameless structures don't have constructors
2612     }
2613
2614     if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
2615     {
2616         return;   // Already added
2617     }
2618
2619     TType ctorType = type;
2620     ctorType.clearArrayness();
2621     ctorType.setPrecision(EbpHigh);
2622     ctorType.setQualifier(EvqTemporary);
2623
2624     TString ctorName = type.getStruct() ? decorate(name) : name;
2625
2626     typedef std::vector<TType> ParameterArray;
2627     ParameterArray ctorParameters;
2628
2629     if (type.getStruct())
2630     {
2631         mStructNames.insert(decorate(name));
2632
2633         TString structure;
2634         structure += "struct " + decorate(name) + "\n"
2635                      "{\n";
2636
2637         const TFieldList &fields = type.getStruct()->fields();
2638
2639         for (unsigned int i = 0; i < fields.size(); i++)
2640         {
2641             const TField *field = fields[i];
2642
2643             structure += "    " + typeString(*field->type()) + " " + decorateField(field->name(), type) + arrayString(*field->type()) + ";\n";
2644         }
2645
2646         structure += "};\n";
2647
2648         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
2649         {
2650             mStructDeclarations.push_back(structure);
2651         }
2652
2653         for (unsigned int i = 0; i < fields.size(); i++)
2654         {
2655             ctorParameters.push_back(*fields[i]->type());
2656         }
2657     }
2658     else if (parameters)
2659     {
2660         for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2661         {
2662             ctorParameters.push_back((*parameter)->getAsTyped()->getType());
2663         }
2664     }
2665     else UNREACHABLE();
2666
2667     TString constructor;
2668
2669     if (ctorType.getStruct())
2670     {
2671         constructor += ctorName + " " + ctorName + "_ctor(";
2672     }
2673     else   // Built-in type
2674     {
2675         constructor += typeString(ctorType) + " " + ctorName + "(";
2676     }
2677
2678     for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
2679     {
2680         const TType &type = ctorParameters[parameter];
2681
2682         constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2683
2684         if (parameter < ctorParameters.size() - 1)
2685         {
2686             constructor += ", ";
2687         }
2688     }
2689
2690     constructor += ")\n"
2691                    "{\n";
2692
2693     if (ctorType.getStruct())
2694     {
2695         constructor += "    " + ctorName + " structure = {";
2696     }
2697     else
2698     {
2699         constructor += "    return " + typeString(ctorType) + "(";
2700     }
2701
2702     if (ctorType.isMatrix() && ctorParameters.size() == 1)
2703     {
2704         int dim = ctorType.getNominalSize();
2705         const TType &parameter = ctorParameters[0];
2706
2707         if (parameter.isScalar())
2708         {
2709             for (int row = 0; row < dim; row++)
2710             {
2711                 for (int col = 0; col < dim; col++)
2712                 {
2713                     constructor += TString((row == col) ? "x0" : "0.0");
2714                     
2715                     if (row < dim - 1 || col < dim - 1)
2716                     {
2717                         constructor += ", ";
2718                     }
2719                 }
2720             }
2721         }
2722         else if (parameter.isMatrix())
2723         {
2724             for (int row = 0; row < dim; row++)
2725             {
2726                 for (int col = 0; col < dim; col++)
2727                 {
2728                     if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2729                     {
2730                         constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2731                     }
2732                     else
2733                     {
2734                         constructor += TString((row == col) ? "1.0" : "0.0");
2735                     }
2736
2737                     if (row < dim - 1 || col < dim - 1)
2738                     {
2739                         constructor += ", ";
2740                     }
2741                 }
2742             }
2743         }
2744         else UNREACHABLE();
2745     }
2746     else
2747     {
2748         size_t remainingComponents = ctorType.getObjectSize();
2749         size_t parameterIndex = 0;
2750
2751         while (remainingComponents > 0)
2752         {
2753             const TType &parameter = ctorParameters[parameterIndex];
2754             const size_t parameterSize = parameter.getObjectSize();
2755             bool moreParameters = parameterIndex + 1 < ctorParameters.size();
2756
2757             constructor += "x" + str(parameterIndex);
2758
2759             if (parameter.isScalar())
2760             {
2761                 ASSERT(parameterSize <= remainingComponents);
2762                 remainingComponents -= parameterSize;
2763             }
2764             else if (parameter.isVector())
2765             {
2766                 if (remainingComponents == parameterSize || moreParameters)
2767                 {
2768                     ASSERT(parameterSize <= remainingComponents);
2769                     remainingComponents -= parameterSize;
2770                 }
2771                 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
2772                 {
2773                     switch (remainingComponents)
2774                     {
2775                       case 1: constructor += ".x";    break;
2776                       case 2: constructor += ".xy";   break;
2777                       case 3: constructor += ".xyz";  break;
2778                       case 4: constructor += ".xyzw"; break;
2779                       default: UNREACHABLE();
2780                     }
2781
2782                     remainingComponents = 0;
2783                 }
2784                 else UNREACHABLE();
2785             }
2786             else if (parameter.isMatrix() || parameter.getStruct())
2787             {
2788                 ASSERT(remainingComponents == parameterSize || moreParameters);
2789                 ASSERT(parameterSize <= remainingComponents);
2790                 
2791                 remainingComponents -= parameterSize;
2792             }
2793             else UNREACHABLE();
2794
2795             if (moreParameters)
2796             {
2797                 parameterIndex++;
2798             }
2799
2800             if (remainingComponents)
2801             {
2802                 constructor += ", ";
2803             }
2804         }
2805     }
2806
2807     if (ctorType.getStruct())
2808     {
2809         constructor += "};\n"
2810                        "    return structure;\n"
2811                        "}\n";
2812     }
2813     else
2814     {
2815         constructor += ");\n"
2816                        "}\n";
2817     }
2818
2819     mConstructors.insert(constructor);
2820 }
2821
2822 const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2823 {
2824     TInfoSinkBase &out = mBody;
2825
2826     if (type.getBasicType() == EbtStruct)
2827     {
2828         out << structLookup(type.getStruct()->name()) + "_ctor(";
2829         
2830         const TFieldList &fields = type.getStruct()->fields();
2831
2832         for (size_t i = 0; i < fields.size(); i++)
2833         {
2834             const TType *fieldType = fields[i]->type();
2835
2836             constUnion = writeConstantUnion(*fieldType, constUnion);
2837
2838             if (i != fields.size() - 1)
2839             {
2840                 out << ", ";
2841             }
2842         }
2843
2844         out << ")";
2845     }
2846     else
2847     {
2848         size_t size = type.getObjectSize();
2849         bool writeType = size > 1;
2850         
2851         if (writeType)
2852         {
2853             out << typeString(type) << "(";
2854         }
2855
2856         for (size_t i = 0; i < size; i++, constUnion++)
2857         {
2858             switch (constUnion->getType())
2859             {
2860               case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
2861               case EbtInt:   out << constUnion->getIConst(); break;
2862               case EbtBool:  out << constUnion->getBConst(); break;
2863               default: UNREACHABLE();
2864             }
2865
2866             if (i != size - 1)
2867             {
2868                 out << ", ";
2869             }
2870         }
2871
2872         if (writeType)
2873         {
2874             out << ")";
2875         }
2876     }
2877
2878     return constUnion;
2879 }
2880
2881 TString OutputHLSL::scopeString(unsigned int depthLimit)
2882 {
2883     TString string;
2884
2885     for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2886     {
2887         string += "_" + str(i);
2888     }
2889
2890     return string;
2891 }
2892
2893 TString OutputHLSL::scopedStruct(const TString &typeName)
2894 {
2895     if (typeName == "")
2896     {
2897         return typeName;
2898     }
2899
2900     return typeName + scopeString(mScopeDepth);
2901 }
2902
2903 TString OutputHLSL::structLookup(const TString &typeName)
2904 {
2905     for (int depth = mScopeDepth; depth >= 0; depth--)
2906     {
2907         TString scopedName = decorate(typeName + scopeString(depth));
2908
2909         for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2910         {
2911             if (*structName == scopedName)
2912             {
2913                 return scopedName;
2914             }
2915         }
2916     }
2917
2918     UNREACHABLE();   // Should have found a matching constructor
2919
2920     return typeName;
2921 }
2922
2923 TString OutputHLSL::decorate(const TString &string)
2924 {
2925     if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
2926     {
2927         return "_" + string;
2928     }
2929     
2930     return string;
2931 }
2932
2933 TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
2934 {
2935     if (type.getBasicType() == EbtSamplerExternalOES)
2936     {
2937         return "ex_" + string;
2938     }
2939     
2940     return decorate(string);
2941 }
2942
2943 TString OutputHLSL::decorateField(const TString &string, const TType &structure)
2944 {
2945     if (structure.getStruct()->name().compare(0, 3, "gl_") != 0)
2946     {
2947         return decorate(string);
2948     }
2949
2950     return string;
2951 }
2952
2953 TString OutputHLSL::registerString(TIntermSymbol *operand)
2954 {
2955     ASSERT(operand->getQualifier() == EvqUniform);
2956
2957     if (IsSampler(operand->getBasicType()))
2958     {
2959         return "s" + str(samplerRegister(operand));
2960     }
2961
2962     return "c" + str(uniformRegister(operand));
2963 }
2964
2965 int OutputHLSL::samplerRegister(TIntermSymbol *sampler)
2966 {
2967     const TType &type = sampler->getType();
2968     ASSERT(IsSampler(type.getBasicType()));
2969
2970     int index = mSamplerRegister;
2971     mSamplerRegister += sampler->totalRegisterCount();
2972
2973     declareUniform(type, sampler->getSymbol(), index);
2974
2975     return index;
2976 }
2977
2978 int OutputHLSL::uniformRegister(TIntermSymbol *uniform)
2979 {
2980     const TType &type = uniform->getType();
2981     ASSERT(!IsSampler(type.getBasicType()));
2982
2983     int index = mUniformRegister;
2984     mUniformRegister += uniform->totalRegisterCount();
2985
2986     declareUniform(type, uniform->getSymbol(), index);
2987
2988     return index;
2989 }
2990
2991 void OutputHLSL::declareUniform(const TType &type, const TString &name, int index)
2992 {
2993     TStructure *structure = type.getStruct();
2994
2995     if (!structure)
2996     {
2997         mActiveUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));
2998     }
2999     else
3000     {
3001         const TFieldList &fields = structure->fields();
3002
3003         if (type.isArray())
3004         {
3005             int elementIndex = index;
3006
3007             for (int i = 0; i < type.getArraySize(); i++)
3008             {
3009                 for (size_t j = 0; j < fields.size(); j++)
3010                 {
3011                     const TType &fieldType = *fields[j]->type();
3012                     const TString uniformName = name + "[" + str(i) + "]." + fields[j]->name();
3013                     declareUniform(fieldType, uniformName, elementIndex);
3014                     elementIndex += fieldType.totalRegisterCount();
3015                 }
3016             }
3017         }
3018         else
3019         {
3020             int fieldIndex = index;
3021
3022             for (size_t i = 0; i < fields.size(); i++)
3023             {
3024                 const TType &fieldType = *fields[i]->type();
3025                 const TString uniformName = name + "." + fields[i]->name();
3026                 declareUniform(fieldType, uniformName, fieldIndex);
3027                 fieldIndex += fieldType.totalRegisterCount();
3028             }
3029         }
3030     }
3031 }
3032
3033 GLenum OutputHLSL::glVariableType(const TType &type)
3034 {
3035     if (type.getBasicType() == EbtFloat)
3036     {
3037         if (type.isScalar())
3038         {
3039             return GL_FLOAT;
3040         }
3041         else if (type.isVector())
3042         {
3043             switch(type.getNominalSize())
3044             {
3045               case 2: return GL_FLOAT_VEC2;
3046               case 3: return GL_FLOAT_VEC3;
3047               case 4: return GL_FLOAT_VEC4;
3048               default: UNREACHABLE();
3049             }
3050         }
3051         else if (type.isMatrix())
3052         {
3053             switch(type.getNominalSize())
3054             {
3055               case 2: return GL_FLOAT_MAT2;
3056               case 3: return GL_FLOAT_MAT3;
3057               case 4: return GL_FLOAT_MAT4;
3058               default: UNREACHABLE();
3059             }
3060         }
3061         else UNREACHABLE();
3062     }
3063     else if (type.getBasicType() == EbtInt)
3064     {
3065         if (type.isScalar())
3066         {
3067             return GL_INT;
3068         }
3069         else if (type.isVector())
3070         {
3071             switch(type.getNominalSize())
3072             {
3073               case 2: return GL_INT_VEC2;
3074               case 3: return GL_INT_VEC3;
3075               case 4: return GL_INT_VEC4;
3076               default: UNREACHABLE();
3077             }
3078         }
3079         else UNREACHABLE();
3080     }
3081     else if (type.getBasicType() == EbtBool)
3082     {
3083         if (type.isScalar())
3084         {
3085             return GL_BOOL;
3086         }
3087         else if (type.isVector())
3088         {
3089             switch(type.getNominalSize())
3090             {
3091               case 2: return GL_BOOL_VEC2;
3092               case 3: return GL_BOOL_VEC3;
3093               case 4: return GL_BOOL_VEC4;
3094               default: UNREACHABLE();
3095             }
3096         }
3097         else UNREACHABLE();
3098     }
3099     else if (type.getBasicType() == EbtSampler2D)
3100     {
3101         return GL_SAMPLER_2D;
3102     }
3103     else if (type.getBasicType() == EbtSamplerCube)
3104     {
3105         return GL_SAMPLER_CUBE;
3106     }
3107     else UNREACHABLE();
3108
3109     return GL_NONE;
3110 }
3111
3112 GLenum OutputHLSL::glVariablePrecision(const TType &type)
3113 {
3114     if (type.getBasicType() == EbtFloat)
3115     {
3116         switch (type.getPrecision())
3117         {
3118           case EbpHigh:   return GL_HIGH_FLOAT;
3119           case EbpMedium: return GL_MEDIUM_FLOAT;
3120           case EbpLow:    return GL_LOW_FLOAT;
3121           case EbpUndefined:
3122             // Should be defined as the default precision by the parser
3123           default: UNREACHABLE();
3124         }
3125     }
3126     else if (type.getBasicType() == EbtInt)
3127     {
3128         switch (type.getPrecision())
3129         {
3130           case EbpHigh:   return GL_HIGH_INT;
3131           case EbpMedium: return GL_MEDIUM_INT;
3132           case EbpLow:    return GL_LOW_INT;
3133           case EbpUndefined:
3134             // Should be defined as the default precision by the parser
3135           default: UNREACHABLE();
3136         }
3137     }
3138
3139     // Other types (boolean, sampler) don't have a precision
3140     return GL_NONE;
3141 }
3142
3143 }