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