blob: 97e1261b61dfbaec6835ce3665f29b4b2112d2ee [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
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.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000013#include <algorithm>
14
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015namespace sh
16{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000017// Integer to TString conversion
18TString str(int i)
19{
20 char buffer[20];
21 sprintf(buffer, "%d", i);
22 return buffer;
23}
24
daniel@transgaming.com950f9932010-04-13 03:26:14 +000025OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000026{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000027 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000028 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000029
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000030 mUsesTexture2D = false;
31 mUsesTexture2D_bias = false;
32 mUsesTexture2DProj = false;
33 mUsesTexture2DProj_bias = false;
34 mUsesTextureCube = false;
35 mUsesTextureCube_bias = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000036 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000037 mUsesFragCoord = false;
38 mUsesPointCoord = false;
39 mUsesFrontFacing = false;
40 mUsesPointSize = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000041 mUsesXor = false;
42 mUsesMod1 = false;
43 mUsesMod2 = false;
44 mUsesMod3 = false;
45 mUsesMod4 = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000046 mUsesFaceforward1 = false;
47 mUsesFaceforward2 = false;
48 mUsesFaceforward3 = false;
49 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000050 mUsesEqualMat2 = false;
51 mUsesEqualMat3 = false;
52 mUsesEqualMat4 = false;
53 mUsesEqualVec2 = false;
54 mUsesEqualVec3 = false;
55 mUsesEqualVec4 = false;
56 mUsesEqualIVec2 = false;
57 mUsesEqualIVec3 = false;
58 mUsesEqualIVec4 = false;
59 mUsesEqualBVec2 = false;
60 mUsesEqualBVec3 = false;
61 mUsesEqualBVec4 = false;
daniel@transgaming.com0f189612010-05-07 13:03:36 +000062 mUsesAtan2 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000063
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +000064 mScopeDepth = 0;
65
daniel@transgaming.com005c7392010-04-15 20:45:27 +000066 mArgumentIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000067}
68
daniel@transgaming.comb5875982010-04-15 20:44:53 +000069OutputHLSL::~OutputHLSL()
70{
71 delete mUnfoldSelect;
72}
73
daniel@transgaming.com950f9932010-04-13 03:26:14 +000074void OutputHLSL::output()
75{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000076 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 +000077 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000078
79 mContext.infoSink.obj << mHeader.c_str();
80 mContext.infoSink.obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000081}
82
daniel@transgaming.comb5875982010-04-15 20:44:53 +000083TInfoSinkBase &OutputHLSL::getBodyStream()
84{
85 return mBody;
86}
87
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +000088int OutputHLSL::vectorSize(const TType &type) const
89{
90 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
91 int arraySize = type.isArray() ? type.getArraySize() : 1;
92
93 return elementSize * arraySize;
94}
95
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096void OutputHLSL::header()
97{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000098 EShLanguage language = mContext.language;
99 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000101 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000102 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000103 out << *structDeclaration;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000104 }
105
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000106 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000107 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000108 out << *constructor;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000109 }
110
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000111 if (language == EShLangFragment)
112 {
113 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000114 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000116 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117 int semanticIndex = 0;
118
119 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
120 {
121 const TSymbol *symbol = (*namedSymbol).second;
122 const TString &name = symbol->getName();
123
124 if (symbol->isVariable())
125 {
126 const TVariable *variable = static_cast<const TVariable*>(symbol);
127 const TType &type = variable->getType();
128 TQualifier qualifier = type.getQualifier();
129
130 if (qualifier == EvqUniform)
131 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000132 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
133 {
134 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
135 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136 }
137 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
138 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000139 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
140 {
141 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000142 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000143
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000144 semanticIndex += type.isArray() ? type.getArraySize() : 1;
145 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000147 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000148 {
149 // Globals are declared and intialized as an aggregate node
150 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000151 else if (qualifier == EvqConst)
152 {
153 // Constants are repeated as literals where used
154 }
155 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156 }
157 }
158
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000159 out << "// Varyings\n";
160 out << varyings;
161 out << "\n"
162 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
163
164 if (mUsesFragCoord)
165 {
166 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
167 }
168
169 if (mUsesPointCoord)
170 {
171 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
172 }
173
174 if (mUsesFrontFacing)
175 {
176 out << "static bool gl_FrontFacing = false;\n";
177 }
178
179 out << "\n";
180
181 if (mUsesFragCoord)
182 {
183 out << "uniform float4 dx_Window;\n"
184 "uniform float2 dx_Depth;\n";
185 }
186
187 if (mUsesFrontFacing)
188 {
189 out << "uniform bool dx_PointsOrLines;\n"
190 "uniform bool dx_FrontCCW;\n";
191 }
192
193 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000195 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000196
197 if (mUsesTexture2D)
198 {
199 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
200 "{\n"
201 " return tex2D(s, t);\n"
202 "}\n"
203 "\n";
204 }
205
206 if (mUsesTexture2D_bias)
207 {
208 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
209 "{\n"
210 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
211 "}\n"
212 "\n";
213 }
214
215 if (mUsesTexture2DProj)
216 {
217 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
218 "{\n"
219 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
220 "}\n"
221 "\n"
222 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
223 "{\n"
224 " return tex2Dproj(s, t);\n"
225 "}\n"
226 "\n";
227 }
228
229 if (mUsesTexture2DProj_bias)
230 {
231 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
232 "{\n"
233 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
234 "}\n"
235 "\n"
236 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
237 "{\n"
238 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
239 "}\n"
240 "\n";
241 }
242
243 if (mUsesTextureCube)
244 {
245 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
246 "{\n"
247 " return texCUBE(s, t);\n"
248 "}\n"
249 "\n";
250 }
251
252 if (mUsesTextureCube_bias)
253 {
254 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
255 "{\n"
256 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
257 "}\n"
258 "\n";
259 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000261 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000262 {
263 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000264 TString attributes;
265 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000267 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268
269 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
270 {
271 const TSymbol *symbol = (*namedSymbol).second;
272 const TString &name = symbol->getName();
273
274 if (symbol->isVariable())
275 {
276 const TVariable *variable = static_cast<const TVariable*>(symbol);
277 const TType &type = variable->getType();
278 TQualifier qualifier = type.getQualifier();
279
280 if (qualifier == EvqUniform)
281 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000282 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
283 {
284 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
285 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000286 }
287 else if (qualifier == EvqAttribute)
288 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000289 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
290 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000291 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000292 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293 }
294 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
295 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000296 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
297 {
298 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000299 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000300 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000302 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000304 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000306 else if (qualifier == EvqConst)
307 {
308 // Constants are repeated as literals where used
309 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310 else UNREACHABLE();
311 }
312 }
313
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000314 out << "// Attributes\n";
315 out << attributes;
316 out << "\n"
317 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
318
319 if (mUsesPointSize)
320 {
321 out << "static float gl_PointSize = float(1);\n";
322 }
323
324 out << "\n"
325 "// Varyings\n";
326 out << varyings;
327 out << "\n"
328 "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000329 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331 out << "\n";
332 }
333
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000334 if (mUsesFragCoord)
335 {
336 out << "#define GL_USES_FRAG_COORD\n";
337 }
338
339 if (mUsesPointCoord)
340 {
341 out << "#define GL_USES_POINT_COORD\n";
342 }
343
344 if (mUsesFrontFacing)
345 {
346 out << "#define GL_USES_FRONT_FACING\n";
347 }
348
349 if (mUsesPointSize)
350 {
351 out << "#define GL_USES_POINT_SIZE\n";
352 }
353
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000354 if (mUsesDepthRange)
355 {
356 out << "struct gl_DepthRangeParameters\n"
357 "{\n"
358 " float near;\n"
359 " float far;\n"
360 " float diff;\n"
361 "};\n"
362 "\n"
363 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
364 "\n";
365 }
366
367 if (mUsesXor)
368 {
369 out << "bool xor(bool p, bool q)\n"
370 "{\n"
371 " return (p || q) && !(p && q);\n"
372 "}\n"
373 "\n";
374 }
375
376 if (mUsesMod1)
377 {
378 out << "float mod(float x, float y)\n"
379 "{\n"
380 " return x - y * floor(x / y);\n"
381 "}\n"
382 "\n";
383 }
384
385 if (mUsesMod2)
386 {
387 out << "float2 mod(float2 x, float y)\n"
388 "{\n"
389 " return x - y * floor(x / y);\n"
390 "}\n"
391 "\n";
392 }
393
394 if (mUsesMod3)
395 {
396 out << "float3 mod(float3 x, float y)\n"
397 "{\n"
398 " return x - y * floor(x / y);\n"
399 "}\n"
400 "\n";
401 }
402
403 if (mUsesMod4)
404 {
405 out << "float4 mod(float4 x, float y)\n"
406 "{\n"
407 " return x - y * floor(x / y);\n"
408 "}\n"
409 "\n";
410 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000411
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000412 if (mUsesFaceforward1)
413 {
414 out << "float faceforward(float N, float I, float Nref)\n"
415 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000416 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000417 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000418 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000419 " }\n"
420 " else\n"
421 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000422 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000423 " }\n"
424 "}\n"
425 "\n";
426 }
427
428 if (mUsesFaceforward2)
429 {
430 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
431 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000432 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000433 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000434 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000435 " }\n"
436 " else\n"
437 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000438 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000439 " }\n"
440 "}\n"
441 "\n";
442 }
443
444 if (mUsesFaceforward3)
445 {
446 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
447 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000448 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000449 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000450 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000451 " }\n"
452 " else\n"
453 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000454 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000455 " }\n"
456 "}\n"
457 "\n";
458 }
459
460 if (mUsesFaceforward4)
461 {
462 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
463 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000464 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000465 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000466 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000467 " }\n"
468 " else\n"
469 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000470 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000471 " }\n"
472 "}\n"
473 "\n";
474 }
475
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000476 if (mUsesEqualMat2)
477 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000478 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000479 "{\n"
480 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
481 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
482 "}\n";
483 }
484
485 if (mUsesEqualMat3)
486 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000487 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000488 "{\n"
489 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
490 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
491 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
492 "}\n";
493 }
494
495 if (mUsesEqualMat4)
496 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000497 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000498 "{\n"
499 " 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"
500 " 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"
501 " 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"
502 " 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"
503 "}\n";
504 }
505
506 if (mUsesEqualVec2)
507 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000508 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000509 "{\n"
510 " return v.x == u.x && v.y == u.y;\n"
511 "}\n";
512 }
513
514 if (mUsesEqualVec3)
515 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000516 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000517 "{\n"
518 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
519 "}\n";
520 }
521
522 if (mUsesEqualVec4)
523 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000524 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000525 "{\n"
526 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
527 "}\n";
528 }
529
530 if (mUsesEqualIVec2)
531 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000532 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000533 "{\n"
534 " return v.x == u.x && v.y == u.y;\n"
535 "}\n";
536 }
537
538 if (mUsesEqualIVec3)
539 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000540 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000541 "{\n"
542 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
543 "}\n";
544 }
545
546 if (mUsesEqualIVec4)
547 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000548 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000549 "{\n"
550 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
551 "}\n";
552 }
553
554 if (mUsesEqualBVec2)
555 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000556 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000557 "{\n"
558 " return v.x == u.x && v.y == u.y;\n"
559 "}\n";
560 }
561
562 if (mUsesEqualBVec3)
563 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000564 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000565 "{\n"
566 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
567 "}\n";
568 }
569
570 if (mUsesEqualBVec4)
571 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000572 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000573 "{\n"
574 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
575 "}\n";
576 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000577
578 if (mUsesAtan2)
579 {
580 out << "float atanyx(float y, float x)\n"
581 "{\n"
582 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
583 " return atan2(y, x);\n"
584 "}\n";
585 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000586}
587
588void OutputHLSL::visitSymbol(TIntermSymbol *node)
589{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000590 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000591
592 TString name = node->getSymbol();
593
594 if (name == "gl_FragColor")
595 {
596 out << "gl_Color[0]";
597 }
598 else if (name == "gl_FragData")
599 {
600 out << "gl_Color";
601 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000602 else if (name == "gl_DepthRange")
603 {
604 mUsesDepthRange = true;
605 out << name;
606 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000607 else if (name == "gl_FragCoord")
608 {
609 mUsesFragCoord = true;
610 out << name;
611 }
612 else if (name == "gl_PointCoord")
613 {
614 mUsesPointCoord = true;
615 out << name;
616 }
617 else if (name == "gl_FrontFacing")
618 {
619 mUsesFrontFacing = true;
620 out << name;
621 }
622 else if (name == "gl_PointSize")
623 {
624 mUsesPointSize = true;
625 out << name;
626 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000627 else
628 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000629 TQualifier qualifier = node->getQualifier();
630
631 if (qualifier == EvqUniform)
632 {
633 mReferencedUniforms.insert(name.c_str());
634 }
635 else if (qualifier == EvqAttribute)
636 {
637 mReferencedAttributes.insert(name.c_str());
638 }
639 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
640 {
641 mReferencedVaryings.insert(name.c_str());
642 }
643
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000644 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645 }
646}
647
648bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
649{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000650 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651
652 switch (node->getOp())
653 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000654 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000655 case EOpInitialize: outputTriplet(visit, "", " = ", ""); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000656 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
657 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
658 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
659 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
660 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
661 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000662 if (visit == PreVisit)
663 {
664 out << "(";
665 }
666 else if (visit == InVisit)
667 {
668 out << " = mul(";
669 node->getLeft()->traverse(this);
670 out << ", transpose(";
671 }
672 else
673 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000674 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000675 }
676 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000677 case EOpMatrixTimesMatrixAssign:
678 if (visit == PreVisit)
679 {
680 out << "(";
681 }
682 else if (visit == InVisit)
683 {
684 out << " = mul(";
685 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000686 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000687 }
688 else
689 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000690 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000691 }
692 break;
693 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000694 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
695 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000696 case EOpIndexDirectStruct:
697 if (visit == InVisit)
698 {
699 out << "." + node->getType().getFieldName();
700
701 return false;
702 }
703 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 case EOpVectorSwizzle:
705 if (visit == InVisit)
706 {
707 out << ".";
708
709 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
710
711 if (swizzle)
712 {
713 TIntermSequence &sequence = swizzle->getSequence();
714
715 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
716 {
717 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
718
719 if (element)
720 {
721 int i = element->getUnionArrayPointer()[0].getIConst();
722
723 switch (i)
724 {
725 case 0: out << "x"; break;
726 case 1: out << "y"; break;
727 case 2: out << "z"; break;
728 case 3: out << "w"; break;
729 default: UNREACHABLE();
730 }
731 }
732 else UNREACHABLE();
733 }
734 }
735 else UNREACHABLE();
736
737 return false; // Fully processed
738 }
739 break;
740 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
741 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
742 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
743 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000744 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000745 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000746 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000747 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000748 if (node->getOp() == EOpEqual)
749 {
750 outputTriplet(visit, "(", " == ", ")");
751 }
752 else
753 {
754 outputTriplet(visit, "(", " != ", ")");
755 }
756 }
757 else if (node->getLeft()->getBasicType() == EbtStruct)
758 {
759 if (node->getOp() == EOpEqual)
760 {
761 out << "(";
762 }
763 else
764 {
765 out << "!(";
766 }
767
768 const TTypeList *fields = node->getLeft()->getType().getStruct();
769
770 for (size_t i = 0; i < fields->size(); i++)
771 {
772 const TType *fieldType = (*fields)[i].type;
773
774 node->getLeft()->traverse(this);
775 out << "." + fieldType->getFieldName() + " == ";
776 node->getRight()->traverse(this);
777 out << "." + fieldType->getFieldName();
778
779 if (i < fields->size() - 1)
780 {
781 out << " && ";
782 }
783 }
784
785 out << ")";
786
787 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000788 }
789 else
790 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000791 if (node->getLeft()->isMatrix())
792 {
793 switch (node->getLeft()->getSize())
794 {
795 case 2 * 2: mUsesEqualMat2 = true; break;
796 case 3 * 3: mUsesEqualMat3 = true; break;
797 case 4 * 4: mUsesEqualMat4 = true; break;
798 default: UNREACHABLE();
799 }
800 }
801 else if (node->getLeft()->isVector())
802 {
803 switch (node->getLeft()->getBasicType())
804 {
805 case EbtFloat:
806 switch (node->getLeft()->getSize())
807 {
808 case 2: mUsesEqualVec2 = true; break;
809 case 3: mUsesEqualVec3 = true; break;
810 case 4: mUsesEqualVec4 = true; break;
811 default: UNREACHABLE();
812 }
813 break;
814 case EbtInt:
815 switch (node->getLeft()->getSize())
816 {
817 case 2: mUsesEqualIVec2 = true; break;
818 case 3: mUsesEqualIVec3 = true; break;
819 case 4: mUsesEqualIVec4 = true; break;
820 default: UNREACHABLE();
821 }
822 break;
823 case EbtBool:
824 switch (node->getLeft()->getSize())
825 {
826 case 2: mUsesEqualBVec2 = true; break;
827 case 3: mUsesEqualBVec3 = true; break;
828 case 4: mUsesEqualBVec4 = true; break;
829 default: UNREACHABLE();
830 }
831 break;
832 default: UNREACHABLE();
833 }
834 }
835 else UNREACHABLE();
836
837 if (node->getOp() == EOpEqual)
838 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000839 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000840 }
841 else
842 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000843 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000844 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000845 }
846 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000847 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
848 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
849 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
850 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
851 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000852 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000853 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
854 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +0000855 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000856 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000857 case EOpLogicalXor:
858 mUsesXor = true;
859 outputTriplet(visit, "xor(", ", ", ")");
860 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000861 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
862 default: UNREACHABLE();
863 }
864
865 return true;
866}
867
868bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
869{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000870 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871
872 switch (node->getOp())
873 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000874 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
875 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
876 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
877 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
878 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
879 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
880 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000881 case EOpConvIntToBool:
882 case EOpConvFloatToBool:
883 switch (node->getOperand()->getType().getNominalSize())
884 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000885 case 1: outputTriplet(visit, "bool(", "", ")"); break;
886 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
887 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
888 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000889 default: UNREACHABLE();
890 }
891 break;
892 case EOpConvBoolToFloat:
893 case EOpConvIntToFloat:
894 switch (node->getOperand()->getType().getNominalSize())
895 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000896 case 1: outputTriplet(visit, "float(", "", ")"); break;
897 case 2: outputTriplet(visit, "float2(", "", ")"); break;
898 case 3: outputTriplet(visit, "float3(", "", ")"); break;
899 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000900 default: UNREACHABLE();
901 }
902 break;
903 case EOpConvFloatToInt:
904 case EOpConvBoolToInt:
905 switch (node->getOperand()->getType().getNominalSize())
906 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000907 case 1: outputTriplet(visit, "int(", "", ")"); break;
908 case 2: outputTriplet(visit, "int2(", "", ")"); break;
909 case 3: outputTriplet(visit, "int3(", "", ")"); break;
910 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000911 default: UNREACHABLE();
912 }
913 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000914 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
915 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
916 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
917 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
918 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
919 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
920 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
921 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
922 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
923 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
924 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
925 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
926 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
927 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
928 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
929 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
930 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
931 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
932 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
933 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
934 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
935// case EOpDPdx: outputTriplet(visit, "ddx(", "", ")"); break;
936// case EOpDPdy: outputTriplet(visit, "ddy(", "", ")"); break;
937// case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
938 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
939 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940 default: UNREACHABLE();
941 }
942
943 return true;
944}
945
946bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
947{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000948 EShLanguage language = mContext.language;
949 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000951 switch (node->getOp())
952 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000953 case EOpSequence:
954 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000955 if (mInsideFunction)
956 {
957 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000958
959 mScopeDepth++;
960
961 if (mScopeBracket.size() < mScopeDepth)
962 {
963 mScopeBracket.push_back(0); // New scope level
964 }
965 else
966 {
967 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
968 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000969 }
970
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000971 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
972 {
973 if (isSingleStatement(*sit))
974 {
975 mUnfoldSelect->traverse(*sit);
976 }
977
978 (*sit)->traverse(this);
979
980 out << ";\n";
981 }
982
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000983 if (mInsideFunction)
984 {
985 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000986
987 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +0000988 }
989
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000990 return false;
991 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000992 case EOpDeclaration:
993 if (visit == PreVisit)
994 {
995 TIntermSequence &sequence = node->getSequence();
996 TIntermTyped *variable = sequence[0]->getAsTyped();
997 bool visit = true;
998
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000999 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001000 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001001 if (variable->getType().getStruct())
1002 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001003 addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001004 }
1005
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001006 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001008 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001009 {
1010 out << "static ";
1011 }
1012
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001013 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001015 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001016 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001017 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001018
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001019 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001020 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001021 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001022 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001023 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001024 }
1025 else
1026 {
1027 (*sit)->traverse(this);
1028 }
1029
1030 if (visit && this->inVisit)
1031 {
1032 if (*sit != sequence.back())
1033 {
1034 visit = this->visitAggregate(InVisit, node);
1035 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036 }
1037 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001039 if (visit && this->postVisit)
1040 {
1041 this->visitAggregate(PostVisit, node);
1042 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001044 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1045 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001046 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001047 }
1048 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 }
1050
1051 return false;
1052 }
1053 else if (visit == InVisit)
1054 {
1055 out << ", ";
1056 }
1057 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001058 case EOpPrototype:
1059 if (visit == PreVisit)
1060 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001061 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001062
1063 TIntermSequence &arguments = node->getSequence();
1064
1065 for (unsigned int i = 0; i < arguments.size(); i++)
1066 {
1067 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1068
1069 if (symbol)
1070 {
1071 out << argumentString(symbol);
1072
1073 if (i < arguments.size() - 1)
1074 {
1075 out << ", ";
1076 }
1077 }
1078 else UNREACHABLE();
1079 }
1080
1081 out << ");\n";
1082
1083 return false;
1084 }
1085 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001086 case EOpComma: outputTriplet(visit, "", ", ", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 case EOpFunction:
1088 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001089 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090
1091 if (visit == PreVisit)
1092 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001093 out << typeString(node->getType()) << " ";
1094
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001095 if (name == "main")
1096 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001097 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001099 else
1100 {
1101 out << decorate(name) << "(";
1102 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001103
1104 TIntermSequence &sequence = node->getSequence();
1105 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1106
1107 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001108 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001109 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001111 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001112 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001113 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001114
1115 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001116 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001117 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001119 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001120 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001122
1123 sequence.erase(sequence.begin());
1124
daniel@transgaming.com63691862010-04-29 03:32:42 +00001125 out << ")\n"
1126 "{\n";
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001127
1128 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001129 }
1130 else if (visit == PostVisit)
1131 {
daniel@transgaming.com63691862010-04-29 03:32:42 +00001132 out << "}\n";
1133
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001134 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135 }
1136 }
1137 break;
1138 case EOpFunctionCall:
1139 {
1140 if (visit == PreVisit)
1141 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001142 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143
1144 if (node->isUserDefined())
1145 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001146 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147 }
1148 else
1149 {
1150 if (name == "texture2D")
1151 {
1152 if (node->getSequence().size() == 2)
1153 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001154 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001155 }
1156 else if (node->getSequence().size() == 3)
1157 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001158 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001159 }
1160 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001161
1162 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163 }
1164 else if (name == "texture2DProj")
1165 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001166 if (node->getSequence().size() == 2)
1167 {
1168 mUsesTexture2DProj = true;
1169 }
1170 else if (node->getSequence().size() == 3)
1171 {
1172 mUsesTexture2DProj_bias = true;
1173 }
1174 else UNREACHABLE();
1175
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001176 out << "gl_texture2DProj(";
1177 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001178 else if (name == "textureCube")
1179 {
1180 if (node->getSequence().size() == 2)
1181 {
1182 mUsesTextureCube = true;
1183 }
1184 else if (node->getSequence().size() == 3)
1185 {
1186 mUsesTextureCube_bias = true;
1187 }
1188 else UNREACHABLE();
1189
1190 out << "gl_textureCube(";
1191 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001192 else if (name == "texture2DLod")
1193 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001194 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001195 }
1196 else if (name == "texture2DProjLod")
1197 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001198 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001200 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001201 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001202 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001204 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205 }
1206 }
1207 else if (visit == InVisit)
1208 {
1209 out << ", ";
1210 }
1211 else
1212 {
1213 out << ")";
1214 }
1215 }
1216 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001217 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001218 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001219 addConstructor(node->getType(), "vec1", &node->getSequence());
1220 outputTriplet(visit, "vec1(", "", ")");
1221 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001222 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001223 addConstructor(node->getType(), "vec2", &node->getSequence());
1224 outputTriplet(visit, "vec2(", ", ", ")");
1225 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001226 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001227 addConstructor(node->getType(), "vec3", &node->getSequence());
1228 outputTriplet(visit, "vec3(", ", ", ")");
1229 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001230 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001231 addConstructor(node->getType(), "vec4", &node->getSequence());
1232 outputTriplet(visit, "vec4(", ", ", ")");
1233 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001234 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001235 addConstructor(node->getType(), "bvec1", &node->getSequence());
1236 outputTriplet(visit, "bvec1(", "", ")");
1237 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001238 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001239 addConstructor(node->getType(), "bvec2", &node->getSequence());
1240 outputTriplet(visit, "bvec2(", ", ", ")");
1241 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001242 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001243 addConstructor(node->getType(), "bvec3", &node->getSequence());
1244 outputTriplet(visit, "bvec3(", ", ", ")");
1245 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001246 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001247 addConstructor(node->getType(), "bvec4", &node->getSequence());
1248 outputTriplet(visit, "bvec4(", ", ", ")");
1249 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001250 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001251 addConstructor(node->getType(), "ivec1", &node->getSequence());
1252 outputTriplet(visit, "ivec1(", "", ")");
1253 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001254 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001255 addConstructor(node->getType(), "ivec2", &node->getSequence());
1256 outputTriplet(visit, "ivec2(", ", ", ")");
1257 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001258 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001259 addConstructor(node->getType(), "ivec3", &node->getSequence());
1260 outputTriplet(visit, "ivec3(", ", ", ")");
1261 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001262 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001263 addConstructor(node->getType(), "ivec4", &node->getSequence());
1264 outputTriplet(visit, "ivec4(", ", ", ")");
1265 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001266 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001267 addConstructor(node->getType(), "mat2", &node->getSequence());
1268 outputTriplet(visit, "mat2(", ", ", ")");
1269 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001270 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001271 addConstructor(node->getType(), "mat3", &node->getSequence());
1272 outputTriplet(visit, "mat3(", ", ", ")");
1273 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001274 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001275 addConstructor(node->getType(), "mat4", &node->getSequence());
1276 outputTriplet(visit, "mat4(", ", ", ")");
1277 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001278 case EOpConstructStruct:
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001279 addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1280 outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001281 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001282 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1283 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1284 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1285 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1286 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1287 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001288 case EOpMod:
1289 {
1290 switch (node->getSequence()[0]->getAsTyped()->getSize()) // Number of components in the first argument
1291 {
1292 case 1: mUsesMod1 = true; break;
1293 case 2: mUsesMod2 = true; break;
1294 case 3: mUsesMod3 = true; break;
1295 case 4: mUsesMod4 = true; break;
1296 default: UNREACHABLE();
1297 }
1298
1299 outputTriplet(visit, "mod(", ", ", ")");
1300 }
1301 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001302 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001303 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001304 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
1305 mUsesAtan2 = true;
1306 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001307 break;
1308 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1309 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1310 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1311 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1312 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1313 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1314 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1315 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1316 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001317 case EOpFaceForward:
1318 {
1319 switch (node->getSequence()[0]->getAsTyped()->getSize()) // Number of components in the first argument
1320 {
1321 case 1: mUsesFaceforward1 = true; break;
1322 case 2: mUsesFaceforward2 = true; break;
1323 case 3: mUsesFaceforward3 = true; break;
1324 case 4: mUsesFaceforward4 = true; break;
1325 default: UNREACHABLE();
1326 }
1327
1328 outputTriplet(visit, "faceforward(", ", ", ")");
1329 }
1330 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1332 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1333 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 default: UNREACHABLE();
1335 }
1336
1337 return true;
1338}
1339
1340bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1341{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001342 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001343
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001344 if (node->usesTernaryOperator())
1345 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001346 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001347 }
1348 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001350 mUnfoldSelect->traverse(node->getCondition());
1351
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001352 out << "if(";
1353
1354 node->getCondition()->traverse(this);
1355
1356 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001357 "{\n";
1358
daniel@transgaming.combb885322010-04-15 20:45:24 +00001359 if (node->getTrueBlock())
1360 {
1361 node->getTrueBlock()->traverse(this);
1362 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001363
1364 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001365
1366 if (node->getFalseBlock())
1367 {
1368 out << "else\n"
1369 "{\n";
1370
1371 node->getFalseBlock()->traverse(this);
1372
1373 out << ";}\n";
1374 }
1375 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001376
1377 return false;
1378}
1379
1380void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1381{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001382 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001383}
1384
1385bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1386{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001387 if (handleExcessiveLoop(node))
1388 {
1389 return false;
1390 }
1391
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001392 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001393
1394 if (!node->testFirst())
1395 {
1396 out << "do\n"
1397 "{\n";
1398 }
1399 else
1400 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001401 if (node->getInit())
1402 {
1403 mUnfoldSelect->traverse(node->getInit());
1404 }
1405
1406 if (node->getTest())
1407 {
1408 mUnfoldSelect->traverse(node->getTest());
1409 }
1410
1411 if (node->getTerminal())
1412 {
1413 mUnfoldSelect->traverse(node->getTerminal());
1414 }
1415
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001416 out << "for(";
1417
1418 if (node->getInit())
1419 {
1420 node->getInit()->traverse(this);
1421 }
1422
1423 out << "; ";
1424
1425 if (node->getTest())
1426 {
1427 node->getTest()->traverse(this);
1428 }
1429
1430 out << "; ";
1431
1432 if (node->getTerminal())
1433 {
1434 node->getTerminal()->traverse(this);
1435 }
1436
1437 out << ")\n"
1438 "{\n";
1439 }
1440
1441 if (node->getBody())
1442 {
1443 node->getBody()->traverse(this);
1444 }
1445
1446 out << "}\n";
1447
1448 if (!node->testFirst())
1449 {
1450 out << "while(\n";
1451
1452 node->getTest()->traverse(this);
1453
1454 out << ")";
1455 }
1456
1457 out << ";\n";
1458
1459 return false;
1460}
1461
1462bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1463{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001464 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001465
1466 switch (node->getFlowOp())
1467 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001468 case EOpKill: outputTriplet(visit, "discard", "", ""); break;
1469 case EOpBreak: outputTriplet(visit, "break", "", ""); break;
1470 case EOpContinue: outputTriplet(visit, "continue", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471 case EOpReturn:
1472 if (visit == PreVisit)
1473 {
1474 if (node->getExpression())
1475 {
1476 out << "return ";
1477 }
1478 else
1479 {
1480 out << "return;\n";
1481 }
1482 }
1483 else if (visit == PostVisit)
1484 {
1485 out << ";\n";
1486 }
1487 break;
1488 default: UNREACHABLE();
1489 }
1490
1491 return true;
1492}
1493
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001494bool OutputHLSL::isSingleStatement(TIntermNode *node)
1495{
1496 TIntermAggregate *aggregate = node->getAsAggregate();
1497
1498 if (aggregate)
1499 {
1500 if (aggregate->getOp() == EOpSequence)
1501 {
1502 return false;
1503 }
1504 else
1505 {
1506 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1507 {
1508 if (!isSingleStatement(*sit))
1509 {
1510 return false;
1511 }
1512 }
1513
1514 return true;
1515 }
1516 }
1517
1518 return true;
1519}
1520
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001521// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1522bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1523{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001524 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001525
1526 // Parse loops of the form:
1527 // for(int index = initial; index [comparator] limit; index += increment)
1528 TIntermSymbol *index = NULL;
1529 TOperator comparator = EOpNull;
1530 int initial = 0;
1531 int limit = 0;
1532 int increment = 0;
1533
1534 // Parse index name and intial value
1535 if (node->getInit())
1536 {
1537 TIntermAggregate *init = node->getInit()->getAsAggregate();
1538
1539 if (init)
1540 {
1541 TIntermSequence &sequence = init->getSequence();
1542 TIntermTyped *variable = sequence[0]->getAsTyped();
1543
1544 if (variable && variable->getQualifier() == EvqTemporary)
1545 {
1546 TIntermBinary *assign = variable->getAsBinaryNode();
1547
1548 if (assign->getOp() == EOpInitialize)
1549 {
1550 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1551 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1552
1553 if (symbol && constant)
1554 {
1555 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1556 {
1557 index = symbol;
1558 initial = constant->getUnionArrayPointer()[0].getIConst();
1559 }
1560 }
1561 }
1562 }
1563 }
1564 }
1565
1566 // Parse comparator and limit value
1567 if (index != NULL && node->getTest())
1568 {
1569 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1570
1571 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1572 {
1573 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1574
1575 if (constant)
1576 {
1577 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1578 {
1579 comparator = test->getOp();
1580 limit = constant->getUnionArrayPointer()[0].getIConst();
1581 }
1582 }
1583 }
1584 }
1585
1586 // Parse increment
1587 if (index != NULL && comparator != EOpNull && node->getTerminal())
1588 {
1589 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1590 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1591
1592 if (binaryTerminal)
1593 {
1594 TOperator op = binaryTerminal->getOp();
1595 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1596
1597 if (constant)
1598 {
1599 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1600 {
1601 int value = constant->getUnionArrayPointer()[0].getIConst();
1602
1603 switch (op)
1604 {
1605 case EOpAddAssign: increment = value; break;
1606 case EOpSubAssign: increment = -value; break;
1607 default: UNIMPLEMENTED();
1608 }
1609 }
1610 }
1611 }
1612 else if (unaryTerminal)
1613 {
1614 TOperator op = unaryTerminal->getOp();
1615
1616 switch (op)
1617 {
1618 case EOpPostIncrement: increment = 1; break;
1619 case EOpPostDecrement: increment = -1; break;
1620 case EOpPreIncrement: increment = 1; break;
1621 case EOpPreDecrement: increment = -1; break;
1622 default: UNIMPLEMENTED();
1623 }
1624 }
1625 }
1626
1627 if (index != NULL && comparator != EOpNull && increment != 0)
1628 {
1629 if (comparator == EOpLessThanEqual)
1630 {
1631 comparator = EOpLessThan;
1632 limit += 1;
1633 }
1634
1635 if (comparator == EOpLessThan)
1636 {
1637 int iterations = (limit - initial + 1) / increment;
1638
1639 if (iterations <= 255)
1640 {
1641 return false; // Not an excessive loop
1642 }
1643
1644 while (iterations > 0)
1645 {
1646 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001647 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001648
1649 // for(int index = initial; index < clampedLimit; index += increment)
1650
1651 out << "for(int ";
1652 index->traverse(this);
1653 out << " = ";
1654 out << initial;
1655
1656 out << "; ";
1657 index->traverse(this);
1658 out << " < ";
1659 out << clampedLimit;
1660
1661 out << "; ";
1662 index->traverse(this);
1663 out << " += ";
1664 out << increment;
1665 out << ")\n"
1666 "{\n";
1667
1668 if (node->getBody())
1669 {
1670 node->getBody()->traverse(this);
1671 }
1672
1673 out << "}\n";
1674
1675 initial += 255 * increment;
1676 iterations -= 255;
1677 }
1678
1679 return true;
1680 }
1681 else UNIMPLEMENTED();
1682 }
1683
1684 return false; // Not handled as an excessive loop
1685}
1686
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001687void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001688{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001689 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001690
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001691 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001692 {
1693 out << preString;
1694 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001695 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001696 {
1697 out << inString;
1698 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001699 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001700 {
1701 out << postString;
1702 }
1703}
1704
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001705TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1706{
1707 TQualifier qualifier = symbol->getQualifier();
1708 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001709 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001710
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001711 if (name.empty()) // HLSL demands named arguments, also for prototypes
1712 {
1713 name = "x" + str(mArgumentIndex++);
1714 }
1715 else
1716 {
1717 name = decorate(name);
1718 }
1719
1720 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001721}
1722
1723TString OutputHLSL::qualifierString(TQualifier qualifier)
1724{
1725 switch(qualifier)
1726 {
1727 case EvqIn: return "in";
1728 case EvqOut: return "out";
1729 case EvqInOut: return "inout";
1730 case EvqConstReadOnly: return "const";
1731 default: UNREACHABLE();
1732 }
1733
1734 return "";
1735}
1736
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001737TString OutputHLSL::typeString(const TType &type)
1738{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001739 if (type.getBasicType() == EbtStruct)
1740 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001741 if (type.getTypeName() != "")
1742 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001743 return structLookup(type.getTypeName());
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001744 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001745 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001746 {
1747 const TTypeList &fields = *type.getStruct();
1748
1749 TString string = "struct\n"
1750 "{\n";
1751
1752 for (unsigned int i = 0; i < fields.size(); i++)
1753 {
1754 const TType &field = *fields[i].type;
1755
1756 string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1757 }
1758
1759 string += "} ";
1760
1761 return string;
1762 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001763 }
1764 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001765 {
1766 switch (type.getNominalSize())
1767 {
1768 case 2: return "float2x2";
1769 case 3: return "float3x3";
1770 case 4: return "float4x4";
1771 }
1772 }
1773 else
1774 {
1775 switch (type.getBasicType())
1776 {
1777 case EbtFloat:
1778 switch (type.getNominalSize())
1779 {
1780 case 1: return "float";
1781 case 2: return "float2";
1782 case 3: return "float3";
1783 case 4: return "float4";
1784 }
1785 case EbtInt:
1786 switch (type.getNominalSize())
1787 {
1788 case 1: return "int";
1789 case 2: return "int2";
1790 case 3: return "int3";
1791 case 4: return "int4";
1792 }
1793 case EbtBool:
1794 switch (type.getNominalSize())
1795 {
1796 case 1: return "bool";
1797 case 2: return "bool2";
1798 case 3: return "bool3";
1799 case 4: return "bool4";
1800 }
1801 case EbtVoid:
1802 return "void";
1803 case EbtSampler2D:
1804 return "sampler2D";
1805 case EbtSamplerCube:
1806 return "samplerCUBE";
1807 }
1808 }
1809
1810 UNIMPLEMENTED(); // FIXME
1811 return "<unknown type>";
1812}
1813
1814TString OutputHLSL::arrayString(const TType &type)
1815{
1816 if (!type.isArray())
1817 {
1818 return "";
1819 }
1820
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001821 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001822}
1823
1824TString OutputHLSL::initializer(const TType &type)
1825{
1826 TString string;
1827
daniel@transgaming.comead23042010-04-29 03:35:36 +00001828 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001829 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001830 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831
daniel@transgaming.comead23042010-04-29 03:35:36 +00001832 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001833 {
1834 string += ", ";
1835 }
1836 }
1837
daniel@transgaming.comead23042010-04-29 03:35:36 +00001838 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001839}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001840
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001841void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00001842{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001843 if (name == "")
1844 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001845 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001846 }
1847
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001848 TType ctorType = type;
1849 ctorType.clearArrayness();
1850 ctorType.changePrecision(EbpHigh);
1851 ctorType.changeQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00001852
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001853 TString ctorName = type.getStruct() ? decorate(name) : name;
1854
1855 typedef std::vector<TType> ParameterArray;
1856 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001857
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001858 if (parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00001859 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001860 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
1861 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001862 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001863 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00001864 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001865 else if (type.getStruct())
1866 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001867 mStructNames.insert(decorate(name));
1868
1869 TString structure;
1870 structure += "struct " + decorate(name) + "\n"
1871 "{\n";
1872
1873 const TTypeList &fields = *type.getStruct();
1874
1875 for (unsigned int i = 0; i < fields.size(); i++)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001876 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001877 const TType &field = *fields[i].type;
1878
1879 structure += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001880 }
1881
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001882 structure += "};\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001883
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001884 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001885 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001886 mStructDeclarations.push_back(structure);
1887 }
1888
1889 for (unsigned int i = 0; i < fields.size(); i++)
1890 {
1891 ctorParameters.push_back(*fields[i].type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001892 }
1893 }
1894 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00001895
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001896 TString constructor;
1897
1898 if (ctorType.getStruct())
1899 {
1900 constructor += ctorName + " " + ctorName + "_ctor(";
1901 }
1902 else // Built-in type
1903 {
1904 constructor += typeString(ctorType) + " " + ctorName + "(";
1905 }
1906
1907 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
1908 {
1909 const TType &type = ctorParameters[parameter];
1910
1911 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
1912
1913 if (parameter < ctorParameters.size() - 1)
1914 {
1915 constructor += ", ";
1916 }
1917 }
1918
1919 constructor += ")\n"
1920 "{\n";
1921
1922 if (ctorType.getStruct())
1923 {
1924 constructor += " " + ctorName + " structure = {";
1925 }
1926 else
1927 {
1928 constructor += " return " + typeString(ctorType) + "(";
1929 }
1930
1931 if (ctorType.isMatrix() && ctorParameters.size() == 1)
1932 {
1933 int dim = ctorType.getNominalSize();
1934 const TType &parameter = ctorParameters[0];
1935
1936 if (parameter.isScalar())
1937 {
1938 for (int row = 0; row < dim; row++)
1939 {
1940 for (int col = 0; col < dim; col++)
1941 {
1942 constructor += TString((row == col) ? "x0" : "0.0");
1943
1944 if (row < dim - 1 || col < dim - 1)
1945 {
1946 constructor += ", ";
1947 }
1948 }
1949 }
1950 }
1951 else if (parameter.isMatrix())
1952 {
1953 for (int row = 0; row < dim; row++)
1954 {
1955 for (int col = 0; col < dim; col++)
1956 {
1957 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
1958 {
1959 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
1960 }
1961 else
1962 {
1963 constructor += TString((row == col) ? "1.0" : "0.0");
1964 }
1965
1966 if (row < dim - 1 || col < dim - 1)
1967 {
1968 constructor += ", ";
1969 }
1970 }
1971 }
1972 }
1973 else UNREACHABLE();
1974 }
1975 else
1976 {
1977 int remainingComponents = ctorType.getObjectSize();
1978 int parameterIndex = 0;
1979
1980 while (remainingComponents > 0)
1981 {
1982 const TType &parameter = ctorParameters[parameterIndex];
1983 bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
1984
1985 constructor += "x" + str(parameterIndex);
1986
1987 if (parameter.isScalar())
1988 {
1989 remainingComponents -= parameter.getObjectSize();
1990 }
1991 else if (parameter.isVector())
1992 {
1993 if (remainingComponents == parameter.getObjectSize() || moreParameters)
1994 {
1995 remainingComponents -= parameter.getObjectSize();
1996 }
1997 else if (remainingComponents < parameter.getNominalSize())
1998 {
1999 switch (remainingComponents)
2000 {
2001 case 1: constructor += ".x"; break;
2002 case 2: constructor += ".xy"; break;
2003 case 3: constructor += ".xyz"; break;
2004 case 4: constructor += ".xyzw"; break;
2005 default: UNREACHABLE();
2006 }
2007
2008 remainingComponents = 0;
2009 }
2010 else UNREACHABLE();
2011 }
2012 else if (parameter.isMatrix() || parameter.getStruct())
2013 {
2014 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2015
2016 remainingComponents -= parameter.getObjectSize();
2017 }
2018 else UNREACHABLE();
2019
2020 if (moreParameters)
2021 {
2022 parameterIndex++;
2023 }
2024
2025 if (remainingComponents)
2026 {
2027 constructor += ", ";
2028 }
2029 }
2030 }
2031
2032 if (ctorType.getStruct())
2033 {
2034 constructor += "};\n"
2035 " return structure;\n"
2036 "}\n";
2037 }
2038 else
2039 {
2040 constructor += ");\n"
2041 "}\n";
2042 }
2043
daniel@transgaming.com63691862010-04-29 03:32:42 +00002044 mConstructors.insert(constructor);
2045}
2046
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002047const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2048{
2049 TInfoSinkBase &out = mBody;
2050
2051 if (type.getBasicType() == EbtStruct)
2052 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002053 out << structLookup(type.getTypeName()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002054
2055 const TTypeList *structure = type.getStruct();
2056
2057 for (size_t i = 0; i < structure->size(); i++)
2058 {
2059 const TType *fieldType = (*structure)[i].type;
2060
2061 constUnion = writeConstantUnion(*fieldType, constUnion);
2062
2063 if (i != structure->size() - 1)
2064 {
2065 out << ", ";
2066 }
2067 }
2068
2069 out << ")";
2070 }
2071 else
2072 {
2073 int size = type.getObjectSize();
2074 bool writeType = size > 1;
2075
2076 if (writeType)
2077 {
2078 out << typeString(type) << "(";
2079 }
2080
2081 for (int i = 0; i < size; i++, constUnion++)
2082 {
2083 switch (constUnion->getType())
2084 {
2085 case EbtFloat: out << constUnion->getFConst(); break;
2086 case EbtInt: out << constUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002087 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002088 default: UNREACHABLE();
2089 }
2090
2091 if (i != size - 1)
2092 {
2093 out << ", ";
2094 }
2095 }
2096
2097 if (writeType)
2098 {
2099 out << ")";
2100 }
2101 }
2102
2103 return constUnion;
2104}
2105
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002106TString OutputHLSL::scopeString(unsigned int depthLimit)
2107{
2108 TString string;
2109
2110 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2111 {
2112 string += "_" + str(i);
2113 }
2114
2115 return string;
2116}
2117
2118TString OutputHLSL::scopedStruct(const TString &typeName)
2119{
2120 if (typeName == "")
2121 {
2122 return typeName;
2123 }
2124
2125 return typeName + scopeString(mScopeDepth);
2126}
2127
2128TString OutputHLSL::structLookup(const TString &typeName)
2129{
2130 for (int depth = mScopeDepth; depth >= 0; depth--)
2131 {
2132 TString scopedName = decorate(typeName + scopeString(depth));
2133
2134 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2135 {
2136 if (*structName == scopedName)
2137 {
2138 return scopedName;
2139 }
2140 }
2141 }
2142
2143 UNREACHABLE(); // Should have found a matching constructor
2144
2145 return typeName;
2146}
2147
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002148TString OutputHLSL::decorate(const TString &string)
2149{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002150 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002151 {
2152 return "_" + string;
2153 }
2154 else
2155 {
2156 return string;
2157 }
2158}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002159}