blob: e10c81f4ff087e101e9c1480f2d9fa49c2d7483e [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.com15795192011-05-11 15:36:20 +00002// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00007#include "compiler/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
alokp@chromium.org91b72322010-06-02 15:50:56 +00009#include "compiler/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "compiler/InfoSink.h"
11#include "compiler/UnfoldSelect.h"
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +000012#include "compiler/SearchSymbol.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
apatrick@chromium.orgbad6c2a2010-07-20 20:19:51 +000014#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000015#include <algorithm>
16
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017namespace sh
18{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000019// Integer to TString conversion
20TString str(int i)
21{
22 char buffer[20];
23 sprintf(buffer, "%d", i);
24 return buffer;
25}
26
daniel@transgaming.com950f9932010-04-13 03:26:14 +000027OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000029 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000030 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000031
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000032 mUsesTexture2D = false;
33 mUsesTexture2D_bias = false;
34 mUsesTexture2DProj = false;
35 mUsesTexture2DProj_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000036 mUsesTexture2DProjLod = false;
37 mUsesTexture2DLod = false;
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000038 mUsesTextureCube = false;
39 mUsesTextureCube_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000040 mUsesTextureCubeLod = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000041 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000042 mUsesFragCoord = false;
43 mUsesPointCoord = false;
44 mUsesFrontFacing = false;
45 mUsesPointSize = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000046 mUsesXor = false;
47 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +000048 mUsesMod2v = false;
49 mUsesMod2f = false;
50 mUsesMod3v = false;
51 mUsesMod3f = false;
52 mUsesMod4v = false;
53 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000054 mUsesFaceforward1 = false;
55 mUsesFaceforward2 = false;
56 mUsesFaceforward3 = false;
57 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000058 mUsesEqualMat2 = false;
59 mUsesEqualMat3 = false;
60 mUsesEqualMat4 = false;
61 mUsesEqualVec2 = false;
62 mUsesEqualVec3 = false;
63 mUsesEqualVec4 = false;
64 mUsesEqualIVec2 = false;
65 mUsesEqualIVec3 = false;
66 mUsesEqualIVec4 = false;
67 mUsesEqualBVec2 = false;
68 mUsesEqualBVec3 = false;
69 mUsesEqualBVec4 = false;
daniel@transgaming.com0f189612010-05-07 13:03:36 +000070 mUsesAtan2 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000071
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +000072 mScopeDepth = 0;
73
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +000074 mUniqueIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
daniel@transgaming.comb5875982010-04-15 20:44:53 +000077OutputHLSL::~OutputHLSL()
78{
79 delete mUnfoldSelect;
80}
81
daniel@transgaming.com950f9932010-04-13 03:26:14 +000082void OutputHLSL::output()
83{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000084 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
daniel@transgaming.com950f9932010-04-13 03:26:14 +000085 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000086
87 mContext.infoSink.obj << mHeader.c_str();
88 mContext.infoSink.obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000089}
90
daniel@transgaming.comb5875982010-04-15 20:44:53 +000091TInfoSinkBase &OutputHLSL::getBodyStream()
92{
93 return mBody;
94}
95
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +000096int OutputHLSL::vectorSize(const TType &type) const
97{
98 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
99 int arraySize = type.isArray() ? type.getArraySize() : 1;
100
101 return elementSize * arraySize;
102}
103
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104void OutputHLSL::header()
105{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000106 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000107 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000109 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000110 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000111 out << *structDeclaration;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000112 }
113
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000114 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000115 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000116 out << *constructor;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000117 }
118
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000119 if (shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120 {
121 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000122 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000124 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 int semanticIndex = 0;
126
127 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
128 {
129 const TSymbol *symbol = (*namedSymbol).second;
130 const TString &name = symbol->getName();
131
132 if (symbol->isVariable())
133 {
134 const TVariable *variable = static_cast<const TVariable*>(symbol);
135 const TType &type = variable->getType();
136 TQualifier qualifier = type.getQualifier();
137
138 if (qualifier == EvqUniform)
139 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000140 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
141 {
apatrick@chromium.org65756022012-01-17 21:45:38 +0000142 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000143 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 }
145 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
146 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000147 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
148 {
149 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000150 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000151
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000152 semanticIndex += type.isArray() ? type.getArraySize() : 1;
153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000155 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000156 {
157 // Globals are declared and intialized as an aggregate node
158 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000159 else if (qualifier == EvqConst)
160 {
161 // Constants are repeated as literals where used
162 }
163 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 }
165 }
166
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000167 out << "// Varyings\n";
168 out << varyings;
169 out << "\n"
170 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
171
172 if (mUsesFragCoord)
173 {
174 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
175 }
176
177 if (mUsesPointCoord)
178 {
179 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
180 }
181
182 if (mUsesFrontFacing)
183 {
184 out << "static bool gl_FrontFacing = false;\n";
185 }
186
187 out << "\n";
188
189 if (mUsesFragCoord)
190 {
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +0000191 out << "uniform float4 dx_Coord;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000192 "uniform float2 dx_Depth;\n";
193 }
194
195 if (mUsesFrontFacing)
196 {
197 out << "uniform bool dx_PointsOrLines;\n"
198 "uniform bool dx_FrontCCW;\n";
199 }
200
201 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000203 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000204
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000205 // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
206 // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
207 // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
208 // convention, the Y coordinate passed to these functions is adjusted to compensate.
209 //
210 // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
211 //
212 // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
213 // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
214 //
215 // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
216 // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
217 // +Y and -Y faces everywhere else throughout the code.
218
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000219 if (mUsesTexture2D)
220 {
221 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
222 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000223 " return tex2D(s, float2(t.x, 1 - t.y));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000224 "}\n"
225 "\n";
226 }
227
228 if (mUsesTexture2D_bias)
229 {
230 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
231 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000232 " return tex2Dbias(s, float4(t.x, 1 - t.y, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000233 "}\n"
234 "\n";
235 }
236
237 if (mUsesTexture2DProj)
238 {
239 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
240 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000241 " return tex2Dproj(s, float4(t.x, t.z - t.y, 0, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000242 "}\n"
243 "\n"
244 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
245 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000246 " return tex2Dproj(s, float4(t.x, t.w - t.y, t.z, t.w));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000247 "}\n"
248 "\n";
249 }
250
251 if (mUsesTexture2DProj_bias)
252 {
253 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
254 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000255 " return tex2Dbias(s, float4(t.x / t.z, 1 - (t.y / t.z), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000256 "}\n"
257 "\n"
258 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
259 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000260 " return tex2Dbias(s, float4(t.x / t.w, 1 - (t.y / t.w), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000261 "}\n"
262 "\n";
263 }
264
265 if (mUsesTextureCube)
266 {
267 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
268 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000269 " return texCUBE(s, float3(t.x, -t.y, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000270 "}\n"
271 "\n";
272 }
273
274 if (mUsesTextureCube_bias)
275 {
276 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
277 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000278 " return texCUBEbias(s, float4(t.x, -t.y, t.z, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000279 "}\n"
280 "\n";
281 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000283 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 {
285 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000286 TString attributes;
287 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000289 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290
291 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
292 {
293 const TSymbol *symbol = (*namedSymbol).second;
294 const TString &name = symbol->getName();
295
296 if (symbol->isVariable())
297 {
298 const TVariable *variable = static_cast<const TVariable*>(symbol);
299 const TType &type = variable->getType();
300 TQualifier qualifier = type.getQualifier();
301
302 if (qualifier == EvqUniform)
303 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000304 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
305 {
apatrick@chromium.org65756022012-01-17 21:45:38 +0000306 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000307 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308 }
309 else if (qualifier == EvqAttribute)
310 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000311 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
312 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000313 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000314 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315 }
316 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
317 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000318 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
319 {
320 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000321 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000322 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000324 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000326 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000328 else if (qualifier == EvqConst)
329 {
330 // Constants are repeated as literals where used
331 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 else UNREACHABLE();
333 }
334 }
335
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000336 out << "// Attributes\n";
337 out << attributes;
338 out << "\n"
339 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
340
341 if (mUsesPointSize)
342 {
343 out << "static float gl_PointSize = float(1);\n";
344 }
345
346 out << "\n"
347 "// Varyings\n";
348 out << varyings;
349 out << "\n"
350 "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000351 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353 out << "\n";
daniel@transgaming.com15795192011-05-11 15:36:20 +0000354
355 // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
356 // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
357 // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
358 // convention, the Y coordinate passed to these functions is adjusted to compensate.
359 //
360 // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
361 //
362 // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
363 // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
364 //
365 // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
366 // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
367 // +Y and -Y faces everywhere else throughout the code.
368
369 if (mUsesTexture2D)
370 {
371 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
372 "{\n"
373 " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, 0));\n"
374 "}\n"
375 "\n";
376 }
377
378 if (mUsesTexture2DLod)
379 {
380 out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
381 "{\n"
382 " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, lod));\n"
383 "}\n"
384 "\n";
385 }
386
387 if (mUsesTexture2DProj)
388 {
389 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
390 "{\n"
391 " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, 0));\n"
392 "}\n"
393 "\n"
394 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
395 "{\n"
396 " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, 0));\n"
397 "}\n"
398 "\n";
399 }
400
401 if (mUsesTexture2DProjLod)
402 {
403 out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
404 "{\n"
405 " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, lod));\n"
406 "}\n"
407 "\n"
408 "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
409 "{\n"
410 " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, lod));\n"
411 "}\n"
412 "\n";
413 }
414
415 if (mUsesTextureCube)
416 {
417 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
418 "{\n"
419 " return texCUBElod(s, float4(t.x, -t.y, t.z, 0));\n"
420 "}\n"
421 "\n";
422 }
423
424 if (mUsesTextureCubeLod)
425 {
426 out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
427 "{\n"
428 " return texCUBElod(s, float4(t.x, -t.y, t.z, lod));\n"
429 "}\n"
430 "\n";
431 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 }
433
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000434 if (mUsesFragCoord)
435 {
436 out << "#define GL_USES_FRAG_COORD\n";
437 }
438
439 if (mUsesPointCoord)
440 {
441 out << "#define GL_USES_POINT_COORD\n";
442 }
443
444 if (mUsesFrontFacing)
445 {
446 out << "#define GL_USES_FRONT_FACING\n";
447 }
448
449 if (mUsesPointSize)
450 {
451 out << "#define GL_USES_POINT_SIZE\n";
452 }
453
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000454 if (mUsesDepthRange)
455 {
456 out << "struct gl_DepthRangeParameters\n"
457 "{\n"
458 " float near;\n"
459 " float far;\n"
460 " float diff;\n"
461 "};\n"
462 "\n"
daniel@transgaming.com31754962010-11-28 02:02:52 +0000463 "uniform float3 dx_DepthRange;"
464 "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000465 "\n";
466 }
467
468 if (mUsesXor)
469 {
470 out << "bool xor(bool p, bool q)\n"
471 "{\n"
472 " return (p || q) && !(p && q);\n"
473 "}\n"
474 "\n";
475 }
476
477 if (mUsesMod1)
478 {
479 out << "float mod(float x, float y)\n"
480 "{\n"
481 " return x - y * floor(x / y);\n"
482 "}\n"
483 "\n";
484 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000485
486 if (mUsesMod2v)
487 {
488 out << "float2 mod(float2 x, float2 y)\n"
489 "{\n"
490 " return x - y * floor(x / y);\n"
491 "}\n"
492 "\n";
493 }
494
495 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000496 {
497 out << "float2 mod(float2 x, float y)\n"
498 "{\n"
499 " return x - y * floor(x / y);\n"
500 "}\n"
501 "\n";
502 }
503
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000504 if (mUsesMod3v)
505 {
506 out << "float3 mod(float3 x, float3 y)\n"
507 "{\n"
508 " return x - y * floor(x / y);\n"
509 "}\n"
510 "\n";
511 }
512
513 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000514 {
515 out << "float3 mod(float3 x, float y)\n"
516 "{\n"
517 " return x - y * floor(x / y);\n"
518 "}\n"
519 "\n";
520 }
521
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000522 if (mUsesMod4v)
523 {
524 out << "float4 mod(float4 x, float4 y)\n"
525 "{\n"
526 " return x - y * floor(x / y);\n"
527 "}\n"
528 "\n";
529 }
530
531 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000532 {
533 out << "float4 mod(float4 x, float y)\n"
534 "{\n"
535 " return x - y * floor(x / y);\n"
536 "}\n"
537 "\n";
538 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000539
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000540 if (mUsesFaceforward1)
541 {
542 out << "float faceforward(float N, float I, float Nref)\n"
543 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000544 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000545 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000546 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000547 " }\n"
548 " else\n"
549 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000550 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000551 " }\n"
552 "}\n"
553 "\n";
554 }
555
556 if (mUsesFaceforward2)
557 {
558 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
559 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000560 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000561 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000562 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000563 " }\n"
564 " else\n"
565 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000566 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000567 " }\n"
568 "}\n"
569 "\n";
570 }
571
572 if (mUsesFaceforward3)
573 {
574 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
575 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000576 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000577 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000578 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000579 " }\n"
580 " else\n"
581 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000582 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000583 " }\n"
584 "}\n"
585 "\n";
586 }
587
588 if (mUsesFaceforward4)
589 {
590 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
591 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000592 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000593 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000594 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000595 " }\n"
596 " else\n"
597 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000598 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000599 " }\n"
600 "}\n"
601 "\n";
602 }
603
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000604 if (mUsesEqualMat2)
605 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000606 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000607 "{\n"
608 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
609 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
610 "}\n";
611 }
612
613 if (mUsesEqualMat3)
614 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000615 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000616 "{\n"
617 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
618 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
619 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
620 "}\n";
621 }
622
623 if (mUsesEqualMat4)
624 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000625 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000626 "{\n"
627 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] && m[0][3] == n[0][3] &&\n"
628 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] && m[1][3] == n[1][3] &&\n"
629 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2] && m[2][3] == n[2][3] &&\n"
630 " m[3][0] == n[3][0] && m[3][1] == n[3][1] && m[3][2] == n[3][2] && m[3][3] == n[3][3];\n"
631 "}\n";
632 }
633
634 if (mUsesEqualVec2)
635 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000636 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000637 "{\n"
638 " return v.x == u.x && v.y == u.y;\n"
639 "}\n";
640 }
641
642 if (mUsesEqualVec3)
643 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000644 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000645 "{\n"
646 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
647 "}\n";
648 }
649
650 if (mUsesEqualVec4)
651 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000652 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000653 "{\n"
654 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
655 "}\n";
656 }
657
658 if (mUsesEqualIVec2)
659 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000660 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000661 "{\n"
662 " return v.x == u.x && v.y == u.y;\n"
663 "}\n";
664 }
665
666 if (mUsesEqualIVec3)
667 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000668 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000669 "{\n"
670 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
671 "}\n";
672 }
673
674 if (mUsesEqualIVec4)
675 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000676 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000677 "{\n"
678 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
679 "}\n";
680 }
681
682 if (mUsesEqualBVec2)
683 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000684 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000685 "{\n"
686 " return v.x == u.x && v.y == u.y;\n"
687 "}\n";
688 }
689
690 if (mUsesEqualBVec3)
691 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000692 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000693 "{\n"
694 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
695 "}\n";
696 }
697
698 if (mUsesEqualBVec4)
699 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000700 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000701 "{\n"
702 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
703 "}\n";
704 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000705
706 if (mUsesAtan2)
707 {
708 out << "float atanyx(float y, float x)\n"
709 "{\n"
710 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
711 " return atan2(y, x);\n"
712 "}\n";
713 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000714}
715
716void OutputHLSL::visitSymbol(TIntermSymbol *node)
717{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000718 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000719
720 TString name = node->getSymbol();
721
722 if (name == "gl_FragColor")
723 {
724 out << "gl_Color[0]";
725 }
726 else if (name == "gl_FragData")
727 {
728 out << "gl_Color";
729 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000730 else if (name == "gl_DepthRange")
731 {
732 mUsesDepthRange = true;
733 out << name;
734 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000735 else if (name == "gl_FragCoord")
736 {
737 mUsesFragCoord = true;
738 out << name;
739 }
740 else if (name == "gl_PointCoord")
741 {
742 mUsesPointCoord = true;
743 out << name;
744 }
745 else if (name == "gl_FrontFacing")
746 {
747 mUsesFrontFacing = true;
748 out << name;
749 }
750 else if (name == "gl_PointSize")
751 {
752 mUsesPointSize = true;
753 out << name;
754 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000755 else
756 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000757 TQualifier qualifier = node->getQualifier();
758
759 if (qualifier == EvqUniform)
760 {
761 mReferencedUniforms.insert(name.c_str());
apatrick@chromium.org65756022012-01-17 21:45:38 +0000762 out << decorateUniform(name, node->getType());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000763 }
764 else if (qualifier == EvqAttribute)
765 {
766 mReferencedAttributes.insert(name.c_str());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000767 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000768 }
769 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
770 {
771 mReferencedVaryings.insert(name.c_str());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000772 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000773 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000774 else
775 {
776 out << decorate(name);
777 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778 }
779}
780
781bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
782{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000783 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784
785 switch (node->getOp())
786 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000787 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000788 case EOpInitialize:
789 if (visit == PreVisit)
790 {
791 // GLSL allows to write things like "float x = x;" where a new variable x is defined
792 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
793 // new variable is created before the assignment is evaluated), so we need to convert
794 // this to "float t = x, x = t;".
795
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000796 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
797 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000798
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000799 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
800 expression->traverse(&searchSymbol);
801 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000802
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000803 if (sameSymbol)
804 {
805 // Type already printed
806 out << "t" + str(mUniqueIndex) + " = ";
807 expression->traverse(this);
808 out << ", ";
809 symbolNode->traverse(this);
810 out << " = t" + str(mUniqueIndex);
811
812 mUniqueIndex++;
813 return false;
814 }
815 }
816 else if (visit == InVisit)
817 {
818 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000819 }
820 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000821 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
822 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
823 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
824 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
825 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
826 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000827 if (visit == PreVisit)
828 {
829 out << "(";
830 }
831 else if (visit == InVisit)
832 {
833 out << " = mul(";
834 node->getLeft()->traverse(this);
835 out << ", transpose(";
836 }
837 else
838 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000839 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000840 }
841 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000842 case EOpMatrixTimesMatrixAssign:
843 if (visit == PreVisit)
844 {
845 out << "(";
846 }
847 else if (visit == InVisit)
848 {
849 out << " = mul(";
850 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000851 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000852 }
853 else
854 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000855 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000856 }
857 break;
858 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000859 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
860 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000861 case EOpIndexDirectStruct:
862 if (visit == InVisit)
863 {
864 out << "." + node->getType().getFieldName();
865
866 return false;
867 }
868 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000869 case EOpVectorSwizzle:
870 if (visit == InVisit)
871 {
872 out << ".";
873
874 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
875
876 if (swizzle)
877 {
878 TIntermSequence &sequence = swizzle->getSequence();
879
880 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
881 {
882 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
883
884 if (element)
885 {
886 int i = element->getUnionArrayPointer()[0].getIConst();
887
888 switch (i)
889 {
890 case 0: out << "x"; break;
891 case 1: out << "y"; break;
892 case 2: out << "z"; break;
893 case 3: out << "w"; break;
894 default: UNREACHABLE();
895 }
896 }
897 else UNREACHABLE();
898 }
899 }
900 else UNREACHABLE();
901
902 return false; // Fully processed
903 }
904 break;
905 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
906 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
907 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
908 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000909 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000910 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000911 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000912 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000913 if (node->getOp() == EOpEqual)
914 {
915 outputTriplet(visit, "(", " == ", ")");
916 }
917 else
918 {
919 outputTriplet(visit, "(", " != ", ")");
920 }
921 }
922 else if (node->getLeft()->getBasicType() == EbtStruct)
923 {
924 if (node->getOp() == EOpEqual)
925 {
926 out << "(";
927 }
928 else
929 {
930 out << "!(";
931 }
932
933 const TTypeList *fields = node->getLeft()->getType().getStruct();
934
935 for (size_t i = 0; i < fields->size(); i++)
936 {
937 const TType *fieldType = (*fields)[i].type;
938
939 node->getLeft()->traverse(this);
940 out << "." + fieldType->getFieldName() + " == ";
941 node->getRight()->traverse(this);
942 out << "." + fieldType->getFieldName();
943
944 if (i < fields->size() - 1)
945 {
946 out << " && ";
947 }
948 }
949
950 out << ")";
951
952 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000953 }
954 else
955 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000956 if (node->getLeft()->isMatrix())
957 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000958 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000959 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000960 case 2: mUsesEqualMat2 = true; break;
961 case 3: mUsesEqualMat3 = true; break;
962 case 4: mUsesEqualMat4 = true; break;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000963 default: UNREACHABLE();
964 }
965 }
966 else if (node->getLeft()->isVector())
967 {
968 switch (node->getLeft()->getBasicType())
969 {
970 case EbtFloat:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000971 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000972 {
973 case 2: mUsesEqualVec2 = true; break;
974 case 3: mUsesEqualVec3 = true; break;
975 case 4: mUsesEqualVec4 = true; break;
976 default: UNREACHABLE();
977 }
978 break;
979 case EbtInt:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000980 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000981 {
982 case 2: mUsesEqualIVec2 = true; break;
983 case 3: mUsesEqualIVec3 = true; break;
984 case 4: mUsesEqualIVec4 = true; break;
985 default: UNREACHABLE();
986 }
987 break;
988 case EbtBool:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000989 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000990 {
991 case 2: mUsesEqualBVec2 = true; break;
992 case 3: mUsesEqualBVec3 = true; break;
993 case 4: mUsesEqualBVec4 = true; break;
994 default: UNREACHABLE();
995 }
996 break;
997 default: UNREACHABLE();
998 }
999 }
1000 else UNREACHABLE();
1001
1002 if (node->getOp() == EOpEqual)
1003 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001004 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001005 }
1006 else
1007 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001008 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001009 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001010 }
1011 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001012 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1013 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1014 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1015 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1016 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001017 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001018 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1019 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001020 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001021 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001022 case EOpLogicalXor:
1023 mUsesXor = true;
1024 outputTriplet(visit, "xor(", ", ", ")");
1025 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001026 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
1027 default: UNREACHABLE();
1028 }
1029
1030 return true;
1031}
1032
1033bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1034{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001035 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036
1037 switch (node->getOp())
1038 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001039 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
1040 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1041 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1042 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1043 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1044 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1045 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 case EOpConvIntToBool:
1047 case EOpConvFloatToBool:
1048 switch (node->getOperand()->getType().getNominalSize())
1049 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001050 case 1: outputTriplet(visit, "bool(", "", ")"); break;
1051 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
1052 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
1053 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001054 default: UNREACHABLE();
1055 }
1056 break;
1057 case EOpConvBoolToFloat:
1058 case EOpConvIntToFloat:
1059 switch (node->getOperand()->getType().getNominalSize())
1060 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001061 case 1: outputTriplet(visit, "float(", "", ")"); break;
1062 case 2: outputTriplet(visit, "float2(", "", ")"); break;
1063 case 3: outputTriplet(visit, "float3(", "", ")"); break;
1064 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065 default: UNREACHABLE();
1066 }
1067 break;
1068 case EOpConvFloatToInt:
1069 case EOpConvBoolToInt:
1070 switch (node->getOperand()->getType().getNominalSize())
1071 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001072 case 1: outputTriplet(visit, "int(", "", ")"); break;
1073 case 2: outputTriplet(visit, "int2(", "", ")"); break;
1074 case 3: outputTriplet(visit, "int3(", "", ")"); break;
1075 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001076 default: UNREACHABLE();
1077 }
1078 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001079 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1080 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1081 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1082 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1083 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1084 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1085 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1086 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
1087 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1088 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1089 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1090 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1091 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1092 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1093 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1094 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1095 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
1096 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1097 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
1098 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1099 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +00001100 case EOpDFdx: outputTriplet(visit, "ddx(", "", ")"); break;
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001101 case EOpDFdy: outputTriplet(visit, "(-ddy(", "", "))"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +00001102 case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001103 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1104 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001105 default: UNREACHABLE();
1106 }
1107
1108 return true;
1109}
1110
1111bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1112{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +00001113 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001114 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001116 switch (node->getOp())
1117 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001118 case EOpSequence:
1119 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001120 if (mInsideFunction)
1121 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001122 outputLineDirective(node->getLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001123 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001124
1125 mScopeDepth++;
1126
1127 if (mScopeBracket.size() < mScopeDepth)
1128 {
1129 mScopeBracket.push_back(0); // New scope level
1130 }
1131 else
1132 {
1133 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
1134 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001135 }
1136
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001137 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1138 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001139 outputLineDirective((*sit)->getLine());
1140
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001141 if (isSingleStatement(*sit))
1142 {
1143 mUnfoldSelect->traverse(*sit);
1144 }
1145
1146 (*sit)->traverse(this);
1147
1148 out << ";\n";
1149 }
1150
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001151 if (mInsideFunction)
1152 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001153 outputLineDirective(node->getEndLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001154 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001155
1156 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001157 }
1158
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001159 return false;
1160 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001161 case EOpDeclaration:
1162 if (visit == PreVisit)
1163 {
1164 TIntermSequence &sequence = node->getSequence();
1165 TIntermTyped *variable = sequence[0]->getAsTyped();
1166 bool visit = true;
1167
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001168 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001169 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001170 if (variable->getType().getStruct())
1171 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001172 addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001173 }
1174
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001175 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001176 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001177 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001178 {
1179 out << "static ";
1180 }
1181
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001182 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001183
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001184 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001186 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001187
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001188 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001189 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001190 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001191 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001192 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001193 }
1194 else
1195 {
1196 (*sit)->traverse(this);
1197 }
1198
1199 if (visit && this->inVisit)
1200 {
1201 if (*sit != sequence.back())
1202 {
1203 visit = this->visitAggregate(InVisit, node);
1204 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205 }
1206 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001207
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001208 if (visit && this->postVisit)
1209 {
1210 this->visitAggregate(PostVisit, node);
1211 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001212 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001213 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1214 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001215 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001216 }
1217 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218 }
1219
1220 return false;
1221 }
1222 else if (visit == InVisit)
1223 {
1224 out << ", ";
1225 }
1226 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001227 case EOpPrototype:
1228 if (visit == PreVisit)
1229 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001230 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001231
1232 TIntermSequence &arguments = node->getSequence();
1233
1234 for (unsigned int i = 0; i < arguments.size(); i++)
1235 {
1236 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1237
1238 if (symbol)
1239 {
1240 out << argumentString(symbol);
1241
1242 if (i < arguments.size() - 1)
1243 {
1244 out << ", ";
1245 }
1246 }
1247 else UNREACHABLE();
1248 }
1249
1250 out << ");\n";
1251
1252 return false;
1253 }
1254 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001255 case EOpComma: outputTriplet(visit, "", ", ", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001256 case EOpFunction:
1257 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001258 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259
1260 if (visit == PreVisit)
1261 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001262 out << typeString(node->getType()) << " ";
1263
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264 if (name == "main")
1265 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001266 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001267 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001268 else
1269 {
1270 out << decorate(name) << "(";
1271 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001272
1273 TIntermSequence &sequence = node->getSequence();
1274 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1275
1276 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001278 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001279
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001280 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001281 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001282 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001283
1284 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001285 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001286 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001287 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001288 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001289 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001290 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001291
1292 sequence.erase(sequence.begin());
1293
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001294 out << ")\n";
1295
1296 outputLineDirective(node->getLine());
1297 out << "{\n";
1298
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001299 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001300 }
1301 else if (visit == PostVisit)
1302 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001303 outputLineDirective(node->getEndLine());
daniel@transgaming.com63691862010-04-29 03:32:42 +00001304 out << "}\n";
1305
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001306 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001307 }
1308 }
1309 break;
1310 case EOpFunctionCall:
1311 {
1312 if (visit == PreVisit)
1313 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001314 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001315
1316 if (node->isUserDefined())
1317 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001318 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001319 }
1320 else
1321 {
1322 if (name == "texture2D")
1323 {
1324 if (node->getSequence().size() == 2)
1325 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001326 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001327 }
1328 else if (node->getSequence().size() == 3)
1329 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001330 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331 }
1332 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001333
1334 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001335 }
1336 else if (name == "texture2DProj")
1337 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001338 if (node->getSequence().size() == 2)
1339 {
1340 mUsesTexture2DProj = true;
1341 }
1342 else if (node->getSequence().size() == 3)
1343 {
1344 mUsesTexture2DProj_bias = true;
1345 }
1346 else UNREACHABLE();
1347
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001348 out << "gl_texture2DProj(";
1349 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001350 else if (name == "textureCube")
1351 {
1352 if (node->getSequence().size() == 2)
1353 {
1354 mUsesTextureCube = true;
1355 }
1356 else if (node->getSequence().size() == 3)
1357 {
1358 mUsesTextureCube_bias = true;
1359 }
1360 else UNREACHABLE();
1361
1362 out << "gl_textureCube(";
1363 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001364 else if (name == "texture2DLod")
1365 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001366 if (node->getSequence().size() == 3)
1367 {
1368 mUsesTexture2DLod = true;
1369 }
1370 else UNREACHABLE();
1371
1372 out << "gl_texture2DLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001373 }
1374 else if (name == "texture2DProjLod")
1375 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001376 if (node->getSequence().size() == 3)
1377 {
1378 mUsesTexture2DProjLod = true;
1379 }
1380 else UNREACHABLE();
1381
1382 out << "gl_texture2DProjLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001383 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001384 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001385 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001386 if (node->getSequence().size() == 3)
1387 {
1388 mUsesTextureCubeLod = true;
1389 }
1390 else UNREACHABLE();
1391
1392 out << "gl_textureCubeLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001393 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001394 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001395 }
1396 }
1397 else if (visit == InVisit)
1398 {
1399 out << ", ";
1400 }
1401 else
1402 {
1403 out << ")";
1404 }
1405 }
1406 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001407 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001408 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001409 addConstructor(node->getType(), "vec1", &node->getSequence());
1410 outputTriplet(visit, "vec1(", "", ")");
1411 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001412 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001413 addConstructor(node->getType(), "vec2", &node->getSequence());
1414 outputTriplet(visit, "vec2(", ", ", ")");
1415 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001416 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001417 addConstructor(node->getType(), "vec3", &node->getSequence());
1418 outputTriplet(visit, "vec3(", ", ", ")");
1419 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001420 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001421 addConstructor(node->getType(), "vec4", &node->getSequence());
1422 outputTriplet(visit, "vec4(", ", ", ")");
1423 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001424 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001425 addConstructor(node->getType(), "bvec1", &node->getSequence());
1426 outputTriplet(visit, "bvec1(", "", ")");
1427 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001428 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001429 addConstructor(node->getType(), "bvec2", &node->getSequence());
1430 outputTriplet(visit, "bvec2(", ", ", ")");
1431 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001432 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001433 addConstructor(node->getType(), "bvec3", &node->getSequence());
1434 outputTriplet(visit, "bvec3(", ", ", ")");
1435 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001436 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001437 addConstructor(node->getType(), "bvec4", &node->getSequence());
1438 outputTriplet(visit, "bvec4(", ", ", ")");
1439 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001440 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001441 addConstructor(node->getType(), "ivec1", &node->getSequence());
1442 outputTriplet(visit, "ivec1(", "", ")");
1443 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001444 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001445 addConstructor(node->getType(), "ivec2", &node->getSequence());
1446 outputTriplet(visit, "ivec2(", ", ", ")");
1447 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001448 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001449 addConstructor(node->getType(), "ivec3", &node->getSequence());
1450 outputTriplet(visit, "ivec3(", ", ", ")");
1451 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001452 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001453 addConstructor(node->getType(), "ivec4", &node->getSequence());
1454 outputTriplet(visit, "ivec4(", ", ", ")");
1455 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001456 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001457 addConstructor(node->getType(), "mat2", &node->getSequence());
1458 outputTriplet(visit, "mat2(", ", ", ")");
1459 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001460 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001461 addConstructor(node->getType(), "mat3", &node->getSequence());
1462 outputTriplet(visit, "mat3(", ", ", ")");
1463 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001464 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001465 addConstructor(node->getType(), "mat4", &node->getSequence());
1466 outputTriplet(visit, "mat4(", ", ", ")");
1467 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001468 case EOpConstructStruct:
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001469 addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1470 outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001471 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001472 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1473 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1474 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1475 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1476 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1477 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001478 case EOpMod:
1479 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001480 // We need to look at the number of components in both arguments
1481 switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
1482 + node->getSequence()[1]->getAsTyped()->getNominalSize())
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001483 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001484 case 11: mUsesMod1 = true; break;
1485 case 22: mUsesMod2v = true; break;
1486 case 21: mUsesMod2f = true; break;
1487 case 33: mUsesMod3v = true; break;
1488 case 31: mUsesMod3f = true; break;
1489 case 44: mUsesMod4v = true; break;
1490 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001491 default: UNREACHABLE();
1492 }
1493
1494 outputTriplet(visit, "mod(", ", ", ")");
1495 }
1496 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001497 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001498 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001499 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
1500 mUsesAtan2 = true;
1501 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001502 break;
1503 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1504 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1505 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1506 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1507 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1508 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1509 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1510 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1511 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001512 case EOpFaceForward:
1513 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001514 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001515 {
1516 case 1: mUsesFaceforward1 = true; break;
1517 case 2: mUsesFaceforward2 = true; break;
1518 case 3: mUsesFaceforward3 = true; break;
1519 case 4: mUsesFaceforward4 = true; break;
1520 default: UNREACHABLE();
1521 }
1522
1523 outputTriplet(visit, "faceforward(", ", ", ")");
1524 }
1525 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001526 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1527 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1528 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529 default: UNREACHABLE();
1530 }
1531
1532 return true;
1533}
1534
1535bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1536{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001537 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001538
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001539 if (node->usesTernaryOperator())
1540 {
daniel@transgaming.comccb38412011-10-04 18:43:40 +00001541 out << "s" << mUnfoldSelect->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001542 }
1543 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001544 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001545 mUnfoldSelect->traverse(node->getCondition());
1546
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001547 out << "if(";
1548
1549 node->getCondition()->traverse(this);
1550
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001551 out << ")\n";
1552
1553 outputLineDirective(node->getLine());
1554 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555
daniel@transgaming.combb885322010-04-15 20:45:24 +00001556 if (node->getTrueBlock())
1557 {
1558 node->getTrueBlock()->traverse(this);
1559 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001560
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001561 outputLineDirective(node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001563
1564 if (node->getFalseBlock())
1565 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001566 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001567
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001568 outputLineDirective(node->getFalseBlock()->getLine());
1569 out << "{\n";
1570
1571 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001572 node->getFalseBlock()->traverse(this);
1573
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001574 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001575 out << ";}\n";
1576 }
1577 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001578
1579 return false;
1580}
1581
1582void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1583{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001584 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001585}
1586
1587bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1588{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001589 if (handleExcessiveLoop(node))
1590 {
1591 return false;
1592 }
1593
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001594 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001595
alokp@chromium.org52813552010-11-16 18:36:09 +00001596 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001597 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001598 out << "do\n";
1599
1600 outputLineDirective(node->getLine());
1601 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001602 }
1603 else
1604 {
1605 out << "for(";
1606
1607 if (node->getInit())
1608 {
1609 node->getInit()->traverse(this);
1610 }
1611
1612 out << "; ";
1613
alokp@chromium.org52813552010-11-16 18:36:09 +00001614 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001615 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001616 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617 }
1618
1619 out << "; ";
1620
alokp@chromium.org52813552010-11-16 18:36:09 +00001621 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001623 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624 }
1625
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001626 out << ")\n";
1627
1628 outputLineDirective(node->getLine());
1629 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630 }
1631
1632 if (node->getBody())
1633 {
1634 node->getBody()->traverse(this);
1635 }
1636
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001637 outputLineDirective(node->getLine());
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00001638 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001639
alokp@chromium.org52813552010-11-16 18:36:09 +00001640 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001641 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001642 outputLineDirective(node->getCondition()->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001643 out << "while(\n";
1644
alokp@chromium.org52813552010-11-16 18:36:09 +00001645 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001646
1647 out << ")";
1648 }
1649
1650 out << ";\n";
1651
1652 return false;
1653}
1654
1655bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1656{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001657 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001658
1659 switch (node->getFlowOp())
1660 {
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00001661 case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
1662 case EOpBreak: outputTriplet(visit, "break;\n", "", ""); break;
1663 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001664 case EOpReturn:
1665 if (visit == PreVisit)
1666 {
1667 if (node->getExpression())
1668 {
1669 out << "return ";
1670 }
1671 else
1672 {
1673 out << "return;\n";
1674 }
1675 }
1676 else if (visit == PostVisit)
1677 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001678 if (node->getExpression())
1679 {
1680 out << ";\n";
1681 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001682 }
1683 break;
1684 default: UNREACHABLE();
1685 }
1686
1687 return true;
1688}
1689
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001690bool OutputHLSL::isSingleStatement(TIntermNode *node)
1691{
1692 TIntermAggregate *aggregate = node->getAsAggregate();
1693
1694 if (aggregate)
1695 {
1696 if (aggregate->getOp() == EOpSequence)
1697 {
1698 return false;
1699 }
1700 else
1701 {
1702 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1703 {
1704 if (!isSingleStatement(*sit))
1705 {
1706 return false;
1707 }
1708 }
1709
1710 return true;
1711 }
1712 }
1713
1714 return true;
1715}
1716
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001717// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1718bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1719{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001720 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001721
1722 // Parse loops of the form:
1723 // for(int index = initial; index [comparator] limit; index += increment)
1724 TIntermSymbol *index = NULL;
1725 TOperator comparator = EOpNull;
1726 int initial = 0;
1727 int limit = 0;
1728 int increment = 0;
1729
1730 // Parse index name and intial value
1731 if (node->getInit())
1732 {
1733 TIntermAggregate *init = node->getInit()->getAsAggregate();
1734
1735 if (init)
1736 {
1737 TIntermSequence &sequence = init->getSequence();
1738 TIntermTyped *variable = sequence[0]->getAsTyped();
1739
1740 if (variable && variable->getQualifier() == EvqTemporary)
1741 {
1742 TIntermBinary *assign = variable->getAsBinaryNode();
1743
1744 if (assign->getOp() == EOpInitialize)
1745 {
1746 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1747 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1748
1749 if (symbol && constant)
1750 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001751 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001752 {
1753 index = symbol;
1754 initial = constant->getUnionArrayPointer()[0].getIConst();
1755 }
1756 }
1757 }
1758 }
1759 }
1760 }
1761
1762 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00001763 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001764 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001765 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001766
1767 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1768 {
1769 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1770
1771 if (constant)
1772 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001773 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001774 {
1775 comparator = test->getOp();
1776 limit = constant->getUnionArrayPointer()[0].getIConst();
1777 }
1778 }
1779 }
1780 }
1781
1782 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00001783 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001784 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001785 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
1786 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001787
1788 if (binaryTerminal)
1789 {
1790 TOperator op = binaryTerminal->getOp();
1791 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1792
1793 if (constant)
1794 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001795 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001796 {
1797 int value = constant->getUnionArrayPointer()[0].getIConst();
1798
1799 switch (op)
1800 {
1801 case EOpAddAssign: increment = value; break;
1802 case EOpSubAssign: increment = -value; break;
1803 default: UNIMPLEMENTED();
1804 }
1805 }
1806 }
1807 }
1808 else if (unaryTerminal)
1809 {
1810 TOperator op = unaryTerminal->getOp();
1811
1812 switch (op)
1813 {
1814 case EOpPostIncrement: increment = 1; break;
1815 case EOpPostDecrement: increment = -1; break;
1816 case EOpPreIncrement: increment = 1; break;
1817 case EOpPreDecrement: increment = -1; break;
1818 default: UNIMPLEMENTED();
1819 }
1820 }
1821 }
1822
1823 if (index != NULL && comparator != EOpNull && increment != 0)
1824 {
1825 if (comparator == EOpLessThanEqual)
1826 {
1827 comparator = EOpLessThan;
1828 limit += 1;
1829 }
1830
1831 if (comparator == EOpLessThan)
1832 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001833 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001834
1835 if (iterations <= 255)
1836 {
1837 return false; // Not an excessive loop
1838 }
1839
1840 while (iterations > 0)
1841 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001842 int remainder = (limit - initial) % increment;
1843 int clampedLimit = initial + increment * std::min(255, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001844
1845 // for(int index = initial; index < clampedLimit; index += increment)
1846
1847 out << "for(int ";
1848 index->traverse(this);
1849 out << " = ";
1850 out << initial;
1851
1852 out << "; ";
1853 index->traverse(this);
1854 out << " < ";
1855 out << clampedLimit;
1856
1857 out << "; ";
1858 index->traverse(this);
1859 out << " += ";
1860 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001861 out << ")\n";
1862
1863 outputLineDirective(node->getLine());
1864 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001865
1866 if (node->getBody())
1867 {
1868 node->getBody()->traverse(this);
1869 }
1870
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001871 outputLineDirective(node->getLine());
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00001872 out << ";}\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001873
1874 initial += 255 * increment;
1875 iterations -= 255;
1876 }
1877
1878 return true;
1879 }
1880 else UNIMPLEMENTED();
1881 }
1882
1883 return false; // Not handled as an excessive loop
1884}
1885
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001886void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001887{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001888 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001889
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001890 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001891 {
1892 out << preString;
1893 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001894 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001895 {
1896 out << inString;
1897 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001898 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001899 {
1900 out << postString;
1901 }
1902}
1903
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001904void OutputHLSL::outputLineDirective(int line)
1905{
1906 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
1907 {
baustin@google.com8ab69842011-06-02 21:53:45 +00001908 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001909 mBody << "#line " << line;
1910
1911 if (mContext.sourcePath)
1912 {
1913 mBody << " \"" << mContext.sourcePath << "\"";
1914 }
1915
1916 mBody << "\n";
1917 }
1918}
1919
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001920TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1921{
1922 TQualifier qualifier = symbol->getQualifier();
1923 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001924 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001925
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001926 if (name.empty()) // HLSL demands named arguments, also for prototypes
1927 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001928 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001929 }
1930 else
1931 {
1932 name = decorate(name);
1933 }
1934
1935 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001936}
1937
1938TString OutputHLSL::qualifierString(TQualifier qualifier)
1939{
1940 switch(qualifier)
1941 {
1942 case EvqIn: return "in";
1943 case EvqOut: return "out";
1944 case EvqInOut: return "inout";
1945 case EvqConstReadOnly: return "const";
1946 default: UNREACHABLE();
1947 }
1948
1949 return "";
1950}
1951
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001952TString OutputHLSL::typeString(const TType &type)
1953{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001954 if (type.getBasicType() == EbtStruct)
1955 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001956 if (type.getTypeName() != "")
1957 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001958 return structLookup(type.getTypeName());
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001959 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001960 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001961 {
1962 const TTypeList &fields = *type.getStruct();
1963
1964 TString string = "struct\n"
1965 "{\n";
1966
1967 for (unsigned int i = 0; i < fields.size(); i++)
1968 {
1969 const TType &field = *fields[i].type;
1970
1971 string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1972 }
1973
1974 string += "} ";
1975
1976 return string;
1977 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001978 }
1979 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001980 {
1981 switch (type.getNominalSize())
1982 {
1983 case 2: return "float2x2";
1984 case 3: return "float3x3";
1985 case 4: return "float4x4";
1986 }
1987 }
1988 else
1989 {
1990 switch (type.getBasicType())
1991 {
1992 case EbtFloat:
1993 switch (type.getNominalSize())
1994 {
1995 case 1: return "float";
1996 case 2: return "float2";
1997 case 3: return "float3";
1998 case 4: return "float4";
1999 }
2000 case EbtInt:
2001 switch (type.getNominalSize())
2002 {
2003 case 1: return "int";
2004 case 2: return "int2";
2005 case 3: return "int3";
2006 case 4: return "int4";
2007 }
2008 case EbtBool:
2009 switch (type.getNominalSize())
2010 {
2011 case 1: return "bool";
2012 case 2: return "bool2";
2013 case 3: return "bool3";
2014 case 4: return "bool4";
2015 }
2016 case EbtVoid:
2017 return "void";
2018 case EbtSampler2D:
2019 return "sampler2D";
2020 case EbtSamplerCube:
2021 return "samplerCUBE";
apatrick@chromium.org65756022012-01-17 21:45:38 +00002022 case EbtSamplerExternalOES:
2023 return "sampler2D";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002024 }
2025 }
2026
2027 UNIMPLEMENTED(); // FIXME
2028 return "<unknown type>";
2029}
2030
2031TString OutputHLSL::arrayString(const TType &type)
2032{
2033 if (!type.isArray())
2034 {
2035 return "";
2036 }
2037
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002038 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002039}
2040
2041TString OutputHLSL::initializer(const TType &type)
2042{
2043 TString string;
2044
daniel@transgaming.comead23042010-04-29 03:35:36 +00002045 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002047 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002048
daniel@transgaming.comead23042010-04-29 03:35:36 +00002049 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002050 {
2051 string += ", ";
2052 }
2053 }
2054
daniel@transgaming.comead23042010-04-29 03:35:36 +00002055 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002056}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002057
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002058void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00002059{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002060 if (name == "")
2061 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00002062 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002063 }
2064
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002065 TType ctorType = type;
2066 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00002067 ctorType.setPrecision(EbpHigh);
2068 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00002069
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002070 TString ctorName = type.getStruct() ? decorate(name) : name;
2071
2072 typedef std::vector<TType> ParameterArray;
2073 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002074
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002075 if (type.getStruct())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002076 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002077 mStructNames.insert(decorate(name));
2078
2079 TString structure;
2080 structure += "struct " + decorate(name) + "\n"
2081 "{\n";
2082
2083 const TTypeList &fields = *type.getStruct();
2084
2085 for (unsigned int i = 0; i < fields.size(); i++)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002086 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002087 const TType &field = *fields[i].type;
2088
2089 structure += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002090 }
2091
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002092 structure += "};\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002093
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002094 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002095 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002096 mStructDeclarations.push_back(structure);
2097 }
2098
2099 for (unsigned int i = 0; i < fields.size(); i++)
2100 {
2101 ctorParameters.push_back(*fields[i].type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002102 }
2103 }
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002104 else if (parameters)
2105 {
2106 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2107 {
2108 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
2109 }
2110 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002111 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00002112
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002113 TString constructor;
2114
2115 if (ctorType.getStruct())
2116 {
2117 constructor += ctorName + " " + ctorName + "_ctor(";
2118 }
2119 else // Built-in type
2120 {
2121 constructor += typeString(ctorType) + " " + ctorName + "(";
2122 }
2123
2124 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
2125 {
2126 const TType &type = ctorParameters[parameter];
2127
2128 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2129
2130 if (parameter < ctorParameters.size() - 1)
2131 {
2132 constructor += ", ";
2133 }
2134 }
2135
2136 constructor += ")\n"
2137 "{\n";
2138
2139 if (ctorType.getStruct())
2140 {
2141 constructor += " " + ctorName + " structure = {";
2142 }
2143 else
2144 {
2145 constructor += " return " + typeString(ctorType) + "(";
2146 }
2147
2148 if (ctorType.isMatrix() && ctorParameters.size() == 1)
2149 {
2150 int dim = ctorType.getNominalSize();
2151 const TType &parameter = ctorParameters[0];
2152
2153 if (parameter.isScalar())
2154 {
2155 for (int row = 0; row < dim; row++)
2156 {
2157 for (int col = 0; col < dim; col++)
2158 {
2159 constructor += TString((row == col) ? "x0" : "0.0");
2160
2161 if (row < dim - 1 || col < dim - 1)
2162 {
2163 constructor += ", ";
2164 }
2165 }
2166 }
2167 }
2168 else if (parameter.isMatrix())
2169 {
2170 for (int row = 0; row < dim; row++)
2171 {
2172 for (int col = 0; col < dim; col++)
2173 {
2174 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2175 {
2176 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2177 }
2178 else
2179 {
2180 constructor += TString((row == col) ? "1.0" : "0.0");
2181 }
2182
2183 if (row < dim - 1 || col < dim - 1)
2184 {
2185 constructor += ", ";
2186 }
2187 }
2188 }
2189 }
2190 else UNREACHABLE();
2191 }
2192 else
2193 {
2194 int remainingComponents = ctorType.getObjectSize();
2195 int parameterIndex = 0;
2196
2197 while (remainingComponents > 0)
2198 {
2199 const TType &parameter = ctorParameters[parameterIndex];
2200 bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
2201
2202 constructor += "x" + str(parameterIndex);
2203
2204 if (parameter.isScalar())
2205 {
2206 remainingComponents -= parameter.getObjectSize();
2207 }
2208 else if (parameter.isVector())
2209 {
2210 if (remainingComponents == parameter.getObjectSize() || moreParameters)
2211 {
2212 remainingComponents -= parameter.getObjectSize();
2213 }
2214 else if (remainingComponents < parameter.getNominalSize())
2215 {
2216 switch (remainingComponents)
2217 {
2218 case 1: constructor += ".x"; break;
2219 case 2: constructor += ".xy"; break;
2220 case 3: constructor += ".xyz"; break;
2221 case 4: constructor += ".xyzw"; break;
2222 default: UNREACHABLE();
2223 }
2224
2225 remainingComponents = 0;
2226 }
2227 else UNREACHABLE();
2228 }
2229 else if (parameter.isMatrix() || parameter.getStruct())
2230 {
2231 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2232
2233 remainingComponents -= parameter.getObjectSize();
2234 }
2235 else UNREACHABLE();
2236
2237 if (moreParameters)
2238 {
2239 parameterIndex++;
2240 }
2241
2242 if (remainingComponents)
2243 {
2244 constructor += ", ";
2245 }
2246 }
2247 }
2248
2249 if (ctorType.getStruct())
2250 {
2251 constructor += "};\n"
2252 " return structure;\n"
2253 "}\n";
2254 }
2255 else
2256 {
2257 constructor += ");\n"
2258 "}\n";
2259 }
2260
daniel@transgaming.com63691862010-04-29 03:32:42 +00002261 mConstructors.insert(constructor);
2262}
2263
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002264const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2265{
2266 TInfoSinkBase &out = mBody;
2267
2268 if (type.getBasicType() == EbtStruct)
2269 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002270 out << structLookup(type.getTypeName()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002271
2272 const TTypeList *structure = type.getStruct();
2273
2274 for (size_t i = 0; i < structure->size(); i++)
2275 {
2276 const TType *fieldType = (*structure)[i].type;
2277
2278 constUnion = writeConstantUnion(*fieldType, constUnion);
2279
2280 if (i != structure->size() - 1)
2281 {
2282 out << ", ";
2283 }
2284 }
2285
2286 out << ")";
2287 }
2288 else
2289 {
2290 int size = type.getObjectSize();
2291 bool writeType = size > 1;
2292
2293 if (writeType)
2294 {
2295 out << typeString(type) << "(";
2296 }
2297
2298 for (int i = 0; i < size; i++, constUnion++)
2299 {
2300 switch (constUnion->getType())
2301 {
2302 case EbtFloat: out << constUnion->getFConst(); break;
2303 case EbtInt: out << constUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002304 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002305 default: UNREACHABLE();
2306 }
2307
2308 if (i != size - 1)
2309 {
2310 out << ", ";
2311 }
2312 }
2313
2314 if (writeType)
2315 {
2316 out << ")";
2317 }
2318 }
2319
2320 return constUnion;
2321}
2322
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002323TString OutputHLSL::scopeString(unsigned int depthLimit)
2324{
2325 TString string;
2326
2327 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2328 {
2329 string += "_" + str(i);
2330 }
2331
2332 return string;
2333}
2334
2335TString OutputHLSL::scopedStruct(const TString &typeName)
2336{
2337 if (typeName == "")
2338 {
2339 return typeName;
2340 }
2341
2342 return typeName + scopeString(mScopeDepth);
2343}
2344
2345TString OutputHLSL::structLookup(const TString &typeName)
2346{
2347 for (int depth = mScopeDepth; depth >= 0; depth--)
2348 {
2349 TString scopedName = decorate(typeName + scopeString(depth));
2350
2351 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2352 {
2353 if (*structName == scopedName)
2354 {
2355 return scopedName;
2356 }
2357 }
2358 }
2359
2360 UNREACHABLE(); // Should have found a matching constructor
2361
2362 return typeName;
2363}
2364
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002365TString OutputHLSL::decorate(const TString &string)
2366{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002367 if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002368 {
2369 return "_" + string;
2370 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002371
2372 return string;
2373}
2374
apatrick@chromium.org65756022012-01-17 21:45:38 +00002375TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002376{
apatrick@chromium.org65756022012-01-17 21:45:38 +00002377 if (type.isArray())
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002378 {
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002379 return "ar_" + string; // Allows identifying arrays of size 1
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002380 }
apatrick@chromium.org65756022012-01-17 21:45:38 +00002381 else if (type.getBasicType() == EbtSamplerExternalOES)
2382 {
2383 return "ex_" + string;
2384 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002385
2386 return decorate(string);
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002387}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002388}