blob: e2ae57dcf226a4f84b8549e9168cac07cc2b8bb1 [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.orgea0e1af2010-03-22 19:33:14 +00009#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010
11#include "compiler/InfoSink.h"
12#include "compiler/UnfoldSelect.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000014#include <algorithm>
15
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000016namespace sh
17{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000018// Integer to TString conversion
19TString str(int i)
20{
21 char buffer[20];
22 sprintf(buffer, "%d", i);
23 return buffer;
24}
25
daniel@transgaming.com950f9932010-04-13 03:26:14 +000026OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000028 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000029 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000030
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000031 mUsesTexture2D = false;
32 mUsesTexture2D_bias = false;
33 mUsesTexture2DProj = false;
34 mUsesTexture2DProj_bias = false;
35 mUsesTextureCube = false;
36 mUsesTextureCube_bias = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000037 mUsesFaceforward1 = false;
38 mUsesFaceforward2 = false;
39 mUsesFaceforward3 = false;
40 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000041 mUsesEqualMat2 = false;
42 mUsesEqualMat3 = false;
43 mUsesEqualMat4 = false;
44 mUsesEqualVec2 = false;
45 mUsesEqualVec3 = false;
46 mUsesEqualVec4 = false;
47 mUsesEqualIVec2 = false;
48 mUsesEqualIVec3 = false;
49 mUsesEqualIVec4 = false;
50 mUsesEqualBVec2 = false;
51 mUsesEqualBVec3 = false;
52 mUsesEqualBVec4 = false;
daniel@transgaming.com0f189612010-05-07 13:03:36 +000053 mUsesAtan2 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000054
55 mArgumentIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000056}
57
daniel@transgaming.comb5875982010-04-15 20:44:53 +000058OutputHLSL::~OutputHLSL()
59{
60 delete mUnfoldSelect;
61}
62
daniel@transgaming.com950f9932010-04-13 03:26:14 +000063void OutputHLSL::output()
64{
65 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
66 header();
67 footer();
68
69 mContext.infoSink.obj << mHeader.c_str();
70 mContext.infoSink.obj << mBody.c_str();
71 mContext.infoSink.obj << mFooter.c_str();
72}
73
daniel@transgaming.comb5875982010-04-15 20:44:53 +000074TInfoSinkBase &OutputHLSL::getBodyStream()
75{
76 return mBody;
77}
78
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +000079int OutputHLSL::vectorSize(const TType &type) const
80{
81 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
82 int arraySize = type.isArray() ? type.getArraySize() : 1;
83
84 return elementSize * arraySize;
85}
86
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087void OutputHLSL::header()
88{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000089 EShLanguage language = mContext.language;
90 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000091
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +000092 // Output structure declarations
93 for (StructureArray::iterator structure = mStructures.begin(); structure != mStructures.end(); structure++)
94 {
95 const TTypeList &fields = *structure->getStruct();
96
97 out << "struct " + decorate(structure->getTypeName()) + "\n"
98 "{\n";
99
100 for (unsigned int i = 0; i < fields.size(); i++)
101 {
102 const TType &field = *fields[i].type;
103
104 out << " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
105 }
106
107 out << "};\n";
108 }
109
110 // Output type constructors
111 for (ConstructorSet::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
112 {
113 out << typeString(constructor->type) + " " + constructor->name + "(";
114
115 for (unsigned int parameter = 0; parameter < constructor->parameters.size(); parameter++)
116 {
117 const TType &type = constructor->parameters[parameter];
118
119 out << typeString(type) + " x" + str(parameter) + arrayString(type);
120
121 if (parameter < constructor->parameters.size() - 1)
122 {
123 out << ", ";
124 }
125 }
126
127 out << ")\n"
128 "{\n";
129
130 if (constructor->type.getStruct())
131 {
132 out << " " + decorate(constructor->type.getTypeName()) + " structure = {";
133 }
134 else
135 {
136 out << " return " + typeString(constructor->type) + "(";
137 }
138
139 if (constructor->type.isMatrix() && constructor->parameters.size() == 1)
140 {
141 int dim = constructor->type.getNominalSize();
142 const TType &parameter = constructor->parameters[0];
143
144 if (parameter.isScalar())
145 {
146 for (int row = 0; row < dim; row++)
147 {
148 for (int col = 0; col < dim; col++)
149 {
150 out << TString((row == col) ? "x0" : "0.0");
151
152 if (row < dim - 1 || col < dim - 1)
153 {
154 out << ", ";
155 }
156 }
157 }
158 }
159 else if (parameter.isMatrix())
160 {
161 for (int row = 0; row < dim; row++)
162 {
163 for (int col = 0; col < dim; col++)
164 {
165 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
166 {
167 out << TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
168 }
169 else
170 {
171 out << TString((row == col) ? "1.0" : "0.0");
172 }
173
174 if (row < dim - 1 || col < dim - 1)
175 {
176 out << ", ";
177 }
178 }
179 }
180 }
181 else UNREACHABLE();
182 }
183 else
184 {
185 int remainingComponents = constructor->type.getObjectSize();
186 int parameterIndex = 0;
187
188 while (remainingComponents > 0)
189 {
190 const TType &parameter = constructor->parameters[parameterIndex];
191 bool moreParameters = parameterIndex < (int)constructor->parameters.size() - 1;
192
193 out << "x" + str(parameterIndex);
194
195 if (parameter.isScalar())
196 {
197 remainingComponents -= parameter.getObjectSize();
198 }
199 else if (parameter.isVector())
200 {
201 if (remainingComponents == parameter.getObjectSize() || moreParameters)
202 {
203 remainingComponents -= parameter.getObjectSize();
204 }
205 else if (remainingComponents < parameter.getNominalSize())
206 {
207 switch (remainingComponents)
208 {
209 case 1: out << ".x"; break;
210 case 2: out << ".xy"; break;
211 case 3: out << ".xyz"; break;
212 case 4: out << ".xyzw"; break;
213 default: UNREACHABLE();
214 }
215
216 remainingComponents = 0;
217 }
218 else UNREACHABLE();
219 }
220 else if (parameter.isMatrix() || parameter.getStruct())
221 {
222 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
223
224 remainingComponents -= parameter.getObjectSize();
225 }
226 else UNREACHABLE();
227
228 if (moreParameters)
229 {
230 parameterIndex++;
231 }
232
233 if (remainingComponents)
234 {
235 out << ", ";
236 }
237 }
238 }
239
240 if (constructor->type.getStruct())
241 {
242 out << "};\n"
243 " return structure;\n"
244 "}\n";
245 }
246 else
247 {
248 out << ");\n"
249 "}\n";
250 }
251 }
252
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253 if (language == EShLangFragment)
254 {
255 TString uniforms;
256 TString varyingInput;
257 TString varyingGlobals;
258
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000259 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 int semanticIndex = 0;
261
262 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
263 {
264 const TSymbol *symbol = (*namedSymbol).second;
265 const TString &name = symbol->getName();
266
267 if (symbol->isVariable())
268 {
269 const TVariable *variable = static_cast<const TVariable*>(symbol);
270 const TType &type = variable->getType();
271 TQualifier qualifier = type.getQualifier();
272
273 if (qualifier == EvqUniform)
274 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000275 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
276 {
277 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
278 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 }
280 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
281 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000282 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
283 {
284 // Program linking depends on this exact format
285 varyingInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
286 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000287
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000288 semanticIndex += type.isArray() ? type.getArraySize() : 1;
289 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000291 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000292 {
293 // Globals are declared and intialized as an aggregate node
294 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000295 else if (qualifier == EvqConst)
296 {
297 // Constants are repeated as literals where used
298 }
299 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 }
301 }
302
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000303 out << "uniform float4 dx_Window;\n"
304 "uniform float2 dx_Depth;\n"
305 "uniform bool dx_PointsOrLines;\n"
306 "uniform bool dx_FrontCCW;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000307 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308 out << uniforms;
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000309 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000310 "struct PS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311 "{\n";
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000312 out << varyingInput;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000313 out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000314 out << " float vFace : VFACE;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000315 "};\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316 "\n";
317 out << varyingGlobals;
318 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000319 "struct PS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320 "{\n"
321 " float4 gl_Color[1] : COLOR;\n"
322 "};\n"
323 "\n"
324 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000325 "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000326 "static float2 gl_PointCoord = float2(0.5, 0.5);\n"
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000327 "static bool gl_FrontFacing = false;\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000329
330 if (mUsesTexture2D)
331 {
332 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
333 "{\n"
334 " return tex2D(s, t);\n"
335 "}\n"
336 "\n";
337 }
338
339 if (mUsesTexture2D_bias)
340 {
341 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
342 "{\n"
343 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
344 "}\n"
345 "\n";
346 }
347
348 if (mUsesTexture2DProj)
349 {
350 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
351 "{\n"
352 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
353 "}\n"
354 "\n"
355 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
356 "{\n"
357 " return tex2Dproj(s, t);\n"
358 "}\n"
359 "\n";
360 }
361
362 if (mUsesTexture2DProj_bias)
363 {
364 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
365 "{\n"
366 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
367 "}\n"
368 "\n"
369 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
370 "{\n"
371 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
372 "}\n"
373 "\n";
374 }
375
376 if (mUsesTextureCube)
377 {
378 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
379 "{\n"
380 " return texCUBE(s, t);\n"
381 "}\n"
382 "\n";
383 }
384
385 if (mUsesTextureCube_bias)
386 {
387 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
388 "{\n"
389 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
390 "}\n"
391 "\n";
392 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000393 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000394 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000395 {
396 TString uniforms;
397 TString attributeInput;
398 TString attributeGlobals;
399 TString varyingOutput;
400 TString varyingGlobals;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000402 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403 int semanticIndex = 0;
404
405 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
406 {
407 const TSymbol *symbol = (*namedSymbol).second;
408 const TString &name = symbol->getName();
409
410 if (symbol->isVariable())
411 {
412 const TVariable *variable = static_cast<const TVariable*>(symbol);
413 const TType &type = variable->getType();
414 TQualifier qualifier = type.getQualifier();
415
416 if (qualifier == EvqUniform)
417 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000418 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
419 {
420 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
421 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422 }
423 else if (qualifier == EvqAttribute)
424 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000425 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
426 {
427 attributeInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
428 attributeGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000429
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000430 semanticIndex += vectorSize(type);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000431 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 }
433 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
434 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000435 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
436 {
437 // Program linking depends on this exact format
438 varyingOutput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
439 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
440 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000442 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000444 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000446 else if (qualifier == EvqConst)
447 {
448 // Constants are repeated as literals where used
449 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 else UNREACHABLE();
451 }
452 }
453
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000454 out << "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000455 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 out << uniforms;
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000457 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000458 "struct VS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459 "{\n";
460 out << attributeInput;
461 out << "};\n"
462 "\n";
463 out << attributeGlobals;
464 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000465 "struct VS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 "{\n"
467 " float4 gl_Position : POSITION;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000468 " float gl_PointSize : PSIZE;\n"
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000469 " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000470 out << varyingOutput;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471 out << "};\n"
472 "\n"
473 "static float4 gl_Position = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000474 "static float gl_PointSize = float(1);\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 out << varyingGlobals;
476 out << "\n";
477 }
478
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000479 out << "struct gl_DepthRangeParameters\n"
480 "{\n"
481 " float near;\n"
482 " float far;\n"
483 " float diff;\n"
484 "};\n"
485 "\n"
486 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
487 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000488 "bool xor(bool p, bool q)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489 "{\n"
490 " return (p || q) && !(p && q);\n"
491 "}\n"
492 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000493 "float mod(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494 "{\n"
495 " return x - y * floor(x / y);\n"
496 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000497 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000498 "float2 mod(float2 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000499 "{\n"
500 " return x - y * floor(x / y);\n"
501 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000502 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000503 "float3 mod(float3 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504 "{\n"
505 " return x - y * floor(x / y);\n"
506 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000507 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000508 "float4 mod(float4 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 "{\n"
510 " return x - y * floor(x / y);\n"
511 "}\n"
512 "\n";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000513
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000514 if (mUsesFaceforward1)
515 {
516 out << "float faceforward(float N, float I, float Nref)\n"
517 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000518 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000519 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000520 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000521 " }\n"
522 " else\n"
523 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000524 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000525 " }\n"
526 "}\n"
527 "\n";
528 }
529
530 if (mUsesFaceforward2)
531 {
532 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
533 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000534 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000535 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000536 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000537 " }\n"
538 " else\n"
539 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000540 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000541 " }\n"
542 "}\n"
543 "\n";
544 }
545
546 if (mUsesFaceforward3)
547 {
548 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
549 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000550 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000551 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000552 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000553 " }\n"
554 " else\n"
555 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000556 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000557 " }\n"
558 "}\n"
559 "\n";
560 }
561
562 if (mUsesFaceforward4)
563 {
564 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
565 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000566 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000567 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000568 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000569 " }\n"
570 " else\n"
571 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000572 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000573 " }\n"
574 "}\n"
575 "\n";
576 }
577
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000578 if (mUsesEqualMat2)
579 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000580 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000581 "{\n"
582 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
583 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
584 "}\n";
585 }
586
587 if (mUsesEqualMat3)
588 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000589 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000590 "{\n"
591 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
592 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
593 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
594 "}\n";
595 }
596
597 if (mUsesEqualMat4)
598 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000599 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000600 "{\n"
601 " 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"
602 " 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"
603 " 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"
604 " 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"
605 "}\n";
606 }
607
608 if (mUsesEqualVec2)
609 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000610 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000611 "{\n"
612 " return v.x == u.x && v.y == u.y;\n"
613 "}\n";
614 }
615
616 if (mUsesEqualVec3)
617 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000618 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000619 "{\n"
620 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
621 "}\n";
622 }
623
624 if (mUsesEqualVec4)
625 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000626 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000627 "{\n"
628 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
629 "}\n";
630 }
631
632 if (mUsesEqualIVec2)
633 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000634 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000635 "{\n"
636 " return v.x == u.x && v.y == u.y;\n"
637 "}\n";
638 }
639
640 if (mUsesEqualIVec3)
641 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000642 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000643 "{\n"
644 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
645 "}\n";
646 }
647
648 if (mUsesEqualIVec4)
649 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000650 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000651 "{\n"
652 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
653 "}\n";
654 }
655
656 if (mUsesEqualBVec2)
657 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000658 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000659 "{\n"
660 " return v.x == u.x && v.y == u.y;\n"
661 "}\n";
662 }
663
664 if (mUsesEqualBVec3)
665 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000666 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000667 "{\n"
668 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
669 "}\n";
670 }
671
672 if (mUsesEqualBVec4)
673 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000674 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000675 "{\n"
676 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
677 "}\n";
678 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000679
680 if (mUsesAtan2)
681 {
682 out << "float atanyx(float y, float x)\n"
683 "{\n"
684 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
685 " return atan2(y, x);\n"
686 "}\n";
687 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688}
689
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000690void OutputHLSL::footer()
691{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000692 EShLanguage language = mContext.language;
693 TInfoSinkBase &out = mFooter;
694 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000695
696 if (language == EShLangFragment)
697 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000698 out << "PS_OUTPUT main(PS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000699 "{\n"
700 " float rhw = 1.0 / input.gl_FragCoord.w;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000701 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Window.x + dx_Window.z;\n"
702 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Window.y + dx_Window.w;\n"
703 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000704 " gl_FragCoord.w = rhw;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000705 " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000706
707 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
708 {
709 const TSymbol *symbol = (*namedSymbol).second;
710 const TString &name = symbol->getName();
711
712 if (symbol->isVariable())
713 {
714 const TVariable *variable = static_cast<const TVariable*>(symbol);
715 const TType &type = variable->getType();
716 TQualifier qualifier = type.getQualifier();
717
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000718 if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000719 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000720 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
721 {
722 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
723 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000724 }
725 }
726 }
727
728 out << "\n"
729 " gl_main();\n"
730 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000731 " PS_OUTPUT output;\n"
732 " output.gl_Color[0] = gl_Color[0];\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000733 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000734 else // Vertex shader
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000735 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000736 out << "VS_OUTPUT main(VS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000737 "{\n";
738
739 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
740 {
741 const TSymbol *symbol = (*namedSymbol).second;
742 const TString &name = symbol->getName();
743
744 if (symbol->isVariable())
745 {
746 const TVariable *variable = static_cast<const TVariable*>(symbol);
747 const TType &type = variable->getType();
748 TQualifier qualifier = type.getQualifier();
749
750 if (qualifier == EvqAttribute)
751 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000752 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
753 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000754 const char *transpose = type.isMatrix() ? "transpose" : "";
755
756 out << " " + decorate(name) + " = " + transpose + "(input." + decorate(name) + ");\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000757 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000758 }
759 }
760 }
761
762 out << "\n"
763 " gl_main();\n"
764 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000765 " VS_OUTPUT output;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000766 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
767 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000768 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
769 " output.gl_Position.w = gl_Position.w;\n"
770 " output.gl_PointSize = gl_PointSize;\n"
771 " output.gl_FragCoord = gl_Position;\n";
772
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000773 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000774
775 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
776 {
777 const TSymbol *symbol = (*namedSymbol).second;
778 const TString &name = symbol->getName();
779
780 if (symbol->isVariable())
781 {
782 const TVariable *variable = static_cast<const TVariable*>(symbol);
783 TQualifier qualifier = variable->getType().getQualifier();
784
785 if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
786 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000787 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
788 {
789 // Program linking depends on this exact format
790 out << " output." + decorate(name) + " = " + decorate(name) + ";\n";
791 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000792 }
793 }
794 }
795 }
796
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000797 out << " return output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000798 "}\n";
799}
800
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000801void OutputHLSL::visitSymbol(TIntermSymbol *node)
802{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000803 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804
805 TString name = node->getSymbol();
806
807 if (name == "gl_FragColor")
808 {
809 out << "gl_Color[0]";
810 }
811 else if (name == "gl_FragData")
812 {
813 out << "gl_Color";
814 }
815 else
816 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000817 TQualifier qualifier = node->getQualifier();
818
819 if (qualifier == EvqUniform)
820 {
821 mReferencedUniforms.insert(name.c_str());
822 }
823 else if (qualifier == EvqAttribute)
824 {
825 mReferencedAttributes.insert(name.c_str());
826 }
827 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
828 {
829 mReferencedVaryings.insert(name.c_str());
830 }
831
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000832 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000833 }
834}
835
836bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
837{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000838 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000839
840 switch (node->getOp())
841 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000842 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000843 case EOpInitialize: outputTriplet(visit, "", " = ", ""); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000844 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
845 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
846 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
847 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
848 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
849 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000850 if (visit == PreVisit)
851 {
852 out << "(";
853 }
854 else if (visit == InVisit)
855 {
856 out << " = mul(";
857 node->getLeft()->traverse(this);
858 out << ", transpose(";
859 }
860 else
861 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000862 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000863 }
864 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000865 case EOpMatrixTimesMatrixAssign:
866 if (visit == PreVisit)
867 {
868 out << "(";
869 }
870 else if (visit == InVisit)
871 {
872 out << " = mul(";
873 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000874 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000875 }
876 else
877 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000878 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000879 }
880 break;
881 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000882 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
883 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000884 case EOpIndexDirectStruct:
885 if (visit == InVisit)
886 {
887 out << "." + node->getType().getFieldName();
888
889 return false;
890 }
891 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000892 case EOpVectorSwizzle:
893 if (visit == InVisit)
894 {
895 out << ".";
896
897 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
898
899 if (swizzle)
900 {
901 TIntermSequence &sequence = swizzle->getSequence();
902
903 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
904 {
905 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
906
907 if (element)
908 {
909 int i = element->getUnionArrayPointer()[0].getIConst();
910
911 switch (i)
912 {
913 case 0: out << "x"; break;
914 case 1: out << "y"; break;
915 case 2: out << "z"; break;
916 case 3: out << "w"; break;
917 default: UNREACHABLE();
918 }
919 }
920 else UNREACHABLE();
921 }
922 }
923 else UNREACHABLE();
924
925 return false; // Fully processed
926 }
927 break;
928 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
929 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
930 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
931 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000932 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000933 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000934 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000935 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000936 if (node->getOp() == EOpEqual)
937 {
938 outputTriplet(visit, "(", " == ", ")");
939 }
940 else
941 {
942 outputTriplet(visit, "(", " != ", ")");
943 }
944 }
945 else if (node->getLeft()->getBasicType() == EbtStruct)
946 {
947 if (node->getOp() == EOpEqual)
948 {
949 out << "(";
950 }
951 else
952 {
953 out << "!(";
954 }
955
956 const TTypeList *fields = node->getLeft()->getType().getStruct();
957
958 for (size_t i = 0; i < fields->size(); i++)
959 {
960 const TType *fieldType = (*fields)[i].type;
961
962 node->getLeft()->traverse(this);
963 out << "." + fieldType->getFieldName() + " == ";
964 node->getRight()->traverse(this);
965 out << "." + fieldType->getFieldName();
966
967 if (i < fields->size() - 1)
968 {
969 out << " && ";
970 }
971 }
972
973 out << ")";
974
975 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000976 }
977 else
978 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000979 if (node->getLeft()->isMatrix())
980 {
981 switch (node->getLeft()->getSize())
982 {
983 case 2 * 2: mUsesEqualMat2 = true; break;
984 case 3 * 3: mUsesEqualMat3 = true; break;
985 case 4 * 4: mUsesEqualMat4 = true; break;
986 default: UNREACHABLE();
987 }
988 }
989 else if (node->getLeft()->isVector())
990 {
991 switch (node->getLeft()->getBasicType())
992 {
993 case EbtFloat:
994 switch (node->getLeft()->getSize())
995 {
996 case 2: mUsesEqualVec2 = true; break;
997 case 3: mUsesEqualVec3 = true; break;
998 case 4: mUsesEqualVec4 = true; break;
999 default: UNREACHABLE();
1000 }
1001 break;
1002 case EbtInt:
1003 switch (node->getLeft()->getSize())
1004 {
1005 case 2: mUsesEqualIVec2 = true; break;
1006 case 3: mUsesEqualIVec3 = true; break;
1007 case 4: mUsesEqualIVec4 = true; break;
1008 default: UNREACHABLE();
1009 }
1010 break;
1011 case EbtBool:
1012 switch (node->getLeft()->getSize())
1013 {
1014 case 2: mUsesEqualBVec2 = true; break;
1015 case 3: mUsesEqualBVec3 = true; break;
1016 case 4: mUsesEqualBVec4 = true; break;
1017 default: UNREACHABLE();
1018 }
1019 break;
1020 default: UNREACHABLE();
1021 }
1022 }
1023 else UNREACHABLE();
1024
1025 if (node->getOp() == EOpEqual)
1026 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001027 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001028 }
1029 else
1030 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001031 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001032 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001033 }
1034 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001035 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1036 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1037 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1038 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1039 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001040 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001041 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1042 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001043 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001045 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
1047 default: UNREACHABLE();
1048 }
1049
1050 return true;
1051}
1052
1053bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1054{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001055 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001056
1057 switch (node->getOp())
1058 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001059 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
1060 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1061 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1062 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1063 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1064 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1065 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001066 case EOpConvIntToBool:
1067 case EOpConvFloatToBool:
1068 switch (node->getOperand()->getType().getNominalSize())
1069 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001070 case 1: outputTriplet(visit, "bool(", "", ")"); break;
1071 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
1072 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
1073 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 default: UNREACHABLE();
1075 }
1076 break;
1077 case EOpConvBoolToFloat:
1078 case EOpConvIntToFloat:
1079 switch (node->getOperand()->getType().getNominalSize())
1080 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001081 case 1: outputTriplet(visit, "float(", "", ")"); break;
1082 case 2: outputTriplet(visit, "float2(", "", ")"); break;
1083 case 3: outputTriplet(visit, "float3(", "", ")"); break;
1084 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 default: UNREACHABLE();
1086 }
1087 break;
1088 case EOpConvFloatToInt:
1089 case EOpConvBoolToInt:
1090 switch (node->getOperand()->getType().getNominalSize())
1091 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001092 case 1: outputTriplet(visit, "int(", "", ")"); break;
1093 case 2: outputTriplet(visit, "int2(", "", ")"); break;
1094 case 3: outputTriplet(visit, "int3(", "", ")"); break;
1095 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 default: UNREACHABLE();
1097 }
1098 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001099 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1100 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1101 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1102 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1103 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1104 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1105 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1106 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
1107 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1108 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1109 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1110 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1111 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1112 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1113 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1114 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1115 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
1116 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1117 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
1118 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1119 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
1120// case EOpDPdx: outputTriplet(visit, "ddx(", "", ")"); break;
1121// case EOpDPdy: outputTriplet(visit, "ddy(", "", ")"); break;
1122// case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
1123 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1124 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001125 default: UNREACHABLE();
1126 }
1127
1128 return true;
1129}
1130
1131bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1132{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001133 EShLanguage language = mContext.language;
1134 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001136 switch (node->getOp())
1137 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001138 case EOpSequence:
1139 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001140 if (mInsideFunction)
1141 {
1142 out << "{\n";
1143 }
1144
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001145 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1146 {
1147 if (isSingleStatement(*sit))
1148 {
1149 mUnfoldSelect->traverse(*sit);
1150 }
1151
1152 (*sit)->traverse(this);
1153
1154 out << ";\n";
1155 }
1156
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001157 if (mInsideFunction)
1158 {
1159 out << "}\n";
1160 }
1161
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001162 return false;
1163 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001164 case EOpDeclaration:
1165 if (visit == PreVisit)
1166 {
1167 TIntermSequence &sequence = node->getSequence();
1168 TIntermTyped *variable = sequence[0]->getAsTyped();
1169 bool visit = true;
1170
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001171 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001172 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001173 if (variable->getType().getStruct())
1174 {
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001175 addConstructor(variable->getType(), variable->getType().getTypeName() + "_ctor", NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001176 }
1177
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001178 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001179 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001180 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001181 {
1182 out << "static ";
1183 }
1184
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001185 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001186
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001187 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001188 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001189 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001191 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001192 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001193 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001194 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001195 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001196 }
1197 else
1198 {
1199 (*sit)->traverse(this);
1200 }
1201
1202 if (visit && this->inVisit)
1203 {
1204 if (*sit != sequence.back())
1205 {
1206 visit = this->visitAggregate(InVisit, node);
1207 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208 }
1209 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001210
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001211 if (visit && this->postVisit)
1212 {
1213 this->visitAggregate(PostVisit, node);
1214 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001216 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1217 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001218 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001219 }
1220 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221 }
1222
1223 return false;
1224 }
1225 else if (visit == InVisit)
1226 {
1227 out << ", ";
1228 }
1229 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001230 case EOpPrototype:
1231 if (visit == PreVisit)
1232 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001233 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001234
1235 TIntermSequence &arguments = node->getSequence();
1236
1237 for (unsigned int i = 0; i < arguments.size(); i++)
1238 {
1239 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1240
1241 if (symbol)
1242 {
1243 out << argumentString(symbol);
1244
1245 if (i < arguments.size() - 1)
1246 {
1247 out << ", ";
1248 }
1249 }
1250 else UNREACHABLE();
1251 }
1252
1253 out << ");\n";
1254
1255 return false;
1256 }
1257 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001258 case EOpComma: outputTriplet(visit, "", ", ", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259 case EOpFunction:
1260 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001261 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001262
1263 if (visit == PreVisit)
1264 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001265 out << typeString(node->getType()) << " ";
1266
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001267 if (name == "main")
1268 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001269 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001270 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001271 else
1272 {
1273 out << decorate(name) << "(";
1274 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001275
1276 TIntermSequence &sequence = node->getSequence();
1277 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1278
1279 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001280 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001281 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001282
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001283 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001284 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001285 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001286
1287 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001288 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001289 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001290 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001291 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001292 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001293 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001294
1295 sequence.erase(sequence.begin());
1296
daniel@transgaming.com63691862010-04-29 03:32:42 +00001297 out << ")\n"
1298 "{\n";
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001299
1300 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001301 }
1302 else if (visit == PostVisit)
1303 {
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.comec55d292010-04-15 20:44:49 +00001366 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001367 }
1368 else if (name == "texture2DProjLod")
1369 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001370 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001371 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001372 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001373 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001374 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001375 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001376 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001377 }
1378 }
1379 else if (visit == InVisit)
1380 {
1381 out << ", ";
1382 }
1383 else
1384 {
1385 out << ")";
1386 }
1387 }
1388 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001389 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001390 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001391 addConstructor(node->getType(), "vec1", &node->getSequence());
1392 outputTriplet(visit, "vec1(", "", ")");
1393 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001394 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001395 addConstructor(node->getType(), "vec2", &node->getSequence());
1396 outputTriplet(visit, "vec2(", ", ", ")");
1397 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001398 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001399 addConstructor(node->getType(), "vec3", &node->getSequence());
1400 outputTriplet(visit, "vec3(", ", ", ")");
1401 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001402 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001403 addConstructor(node->getType(), "vec4", &node->getSequence());
1404 outputTriplet(visit, "vec4(", ", ", ")");
1405 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001406 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001407 addConstructor(node->getType(), "bvec1", &node->getSequence());
1408 outputTriplet(visit, "bvec1(", "", ")");
1409 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001410 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001411 addConstructor(node->getType(), "bvec2", &node->getSequence());
1412 outputTriplet(visit, "bvec2(", ", ", ")");
1413 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001414 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001415 addConstructor(node->getType(), "bvec3", &node->getSequence());
1416 outputTriplet(visit, "bvec3(", ", ", ")");
1417 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001418 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001419 addConstructor(node->getType(), "bvec4", &node->getSequence());
1420 outputTriplet(visit, "bvec4(", ", ", ")");
1421 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001422 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001423 addConstructor(node->getType(), "ivec1", &node->getSequence());
1424 outputTriplet(visit, "ivec1(", "", ")");
1425 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001426 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001427 addConstructor(node->getType(), "ivec2", &node->getSequence());
1428 outputTriplet(visit, "ivec2(", ", ", ")");
1429 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001430 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001431 addConstructor(node->getType(), "ivec3", &node->getSequence());
1432 outputTriplet(visit, "ivec3(", ", ", ")");
1433 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001434 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001435 addConstructor(node->getType(), "ivec4", &node->getSequence());
1436 outputTriplet(visit, "ivec4(", ", ", ")");
1437 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001438 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001439 addConstructor(node->getType(), "mat2", &node->getSequence());
1440 outputTriplet(visit, "mat2(", ", ", ")");
1441 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001442 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001443 addConstructor(node->getType(), "mat3", &node->getSequence());
1444 outputTriplet(visit, "mat3(", ", ", ")");
1445 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001446 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001447 addConstructor(node->getType(), "mat4", &node->getSequence());
1448 outputTriplet(visit, "mat4(", ", ", ")");
1449 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001450 case EOpConstructStruct:
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001451 addConstructor(node->getType(), node->getType().getTypeName() + "_ctor", &node->getSequence());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001452 outputTriplet(visit, node->getType().getTypeName() + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001453 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001454 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1455 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1456 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1457 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1458 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1459 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001460 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001461 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001462 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001463 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
1464 mUsesAtan2 = true;
1465 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001466 break;
1467 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1468 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1469 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1470 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1471 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1472 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1473 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1474 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1475 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001476 case EOpFaceForward:
1477 {
1478 switch (node->getSequence()[0]->getAsTyped()->getSize()) // Number of components in the first argument
1479 {
1480 case 1: mUsesFaceforward1 = true; break;
1481 case 2: mUsesFaceforward2 = true; break;
1482 case 3: mUsesFaceforward3 = true; break;
1483 case 4: mUsesFaceforward4 = true; break;
1484 default: UNREACHABLE();
1485 }
1486
1487 outputTriplet(visit, "faceforward(", ", ", ")");
1488 }
1489 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001490 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1491 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1492 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493 default: UNREACHABLE();
1494 }
1495
1496 return true;
1497}
1498
1499bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1500{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001501 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001502
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001503 if (node->usesTernaryOperator())
1504 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001505 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001506 }
1507 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001508 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001509 mUnfoldSelect->traverse(node->getCondition());
1510
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001511 out << "if(";
1512
1513 node->getCondition()->traverse(this);
1514
1515 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001516 "{\n";
1517
daniel@transgaming.combb885322010-04-15 20:45:24 +00001518 if (node->getTrueBlock())
1519 {
1520 node->getTrueBlock()->traverse(this);
1521 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001522
1523 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001524
1525 if (node->getFalseBlock())
1526 {
1527 out << "else\n"
1528 "{\n";
1529
1530 node->getFalseBlock()->traverse(this);
1531
1532 out << ";}\n";
1533 }
1534 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001535
1536 return false;
1537}
1538
1539void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1540{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001541 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001542}
1543
1544bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1545{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001546 if (handleExcessiveLoop(node))
1547 {
1548 return false;
1549 }
1550
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001551 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552
1553 if (!node->testFirst())
1554 {
1555 out << "do\n"
1556 "{\n";
1557 }
1558 else
1559 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001560 if (node->getInit())
1561 {
1562 mUnfoldSelect->traverse(node->getInit());
1563 }
1564
1565 if (node->getTest())
1566 {
1567 mUnfoldSelect->traverse(node->getTest());
1568 }
1569
1570 if (node->getTerminal())
1571 {
1572 mUnfoldSelect->traverse(node->getTerminal());
1573 }
1574
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001575 out << "for(";
1576
1577 if (node->getInit())
1578 {
1579 node->getInit()->traverse(this);
1580 }
1581
1582 out << "; ";
1583
1584 if (node->getTest())
1585 {
1586 node->getTest()->traverse(this);
1587 }
1588
1589 out << "; ";
1590
1591 if (node->getTerminal())
1592 {
1593 node->getTerminal()->traverse(this);
1594 }
1595
1596 out << ")\n"
1597 "{\n";
1598 }
1599
1600 if (node->getBody())
1601 {
1602 node->getBody()->traverse(this);
1603 }
1604
1605 out << "}\n";
1606
1607 if (!node->testFirst())
1608 {
1609 out << "while(\n";
1610
1611 node->getTest()->traverse(this);
1612
1613 out << ")";
1614 }
1615
1616 out << ";\n";
1617
1618 return false;
1619}
1620
1621bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1622{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001623 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624
1625 switch (node->getFlowOp())
1626 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001627 case EOpKill: outputTriplet(visit, "discard", "", ""); break;
1628 case EOpBreak: outputTriplet(visit, "break", "", ""); break;
1629 case EOpContinue: outputTriplet(visit, "continue", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630 case EOpReturn:
1631 if (visit == PreVisit)
1632 {
1633 if (node->getExpression())
1634 {
1635 out << "return ";
1636 }
1637 else
1638 {
1639 out << "return;\n";
1640 }
1641 }
1642 else if (visit == PostVisit)
1643 {
1644 out << ";\n";
1645 }
1646 break;
1647 default: UNREACHABLE();
1648 }
1649
1650 return true;
1651}
1652
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001653bool OutputHLSL::isSingleStatement(TIntermNode *node)
1654{
1655 TIntermAggregate *aggregate = node->getAsAggregate();
1656
1657 if (aggregate)
1658 {
1659 if (aggregate->getOp() == EOpSequence)
1660 {
1661 return false;
1662 }
1663 else
1664 {
1665 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1666 {
1667 if (!isSingleStatement(*sit))
1668 {
1669 return false;
1670 }
1671 }
1672
1673 return true;
1674 }
1675 }
1676
1677 return true;
1678}
1679
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001680// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1681bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1682{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001683 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001684
1685 // Parse loops of the form:
1686 // for(int index = initial; index [comparator] limit; index += increment)
1687 TIntermSymbol *index = NULL;
1688 TOperator comparator = EOpNull;
1689 int initial = 0;
1690 int limit = 0;
1691 int increment = 0;
1692
1693 // Parse index name and intial value
1694 if (node->getInit())
1695 {
1696 TIntermAggregate *init = node->getInit()->getAsAggregate();
1697
1698 if (init)
1699 {
1700 TIntermSequence &sequence = init->getSequence();
1701 TIntermTyped *variable = sequence[0]->getAsTyped();
1702
1703 if (variable && variable->getQualifier() == EvqTemporary)
1704 {
1705 TIntermBinary *assign = variable->getAsBinaryNode();
1706
1707 if (assign->getOp() == EOpInitialize)
1708 {
1709 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1710 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1711
1712 if (symbol && constant)
1713 {
1714 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1715 {
1716 index = symbol;
1717 initial = constant->getUnionArrayPointer()[0].getIConst();
1718 }
1719 }
1720 }
1721 }
1722 }
1723 }
1724
1725 // Parse comparator and limit value
1726 if (index != NULL && node->getTest())
1727 {
1728 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1729
1730 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1731 {
1732 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1733
1734 if (constant)
1735 {
1736 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1737 {
1738 comparator = test->getOp();
1739 limit = constant->getUnionArrayPointer()[0].getIConst();
1740 }
1741 }
1742 }
1743 }
1744
1745 // Parse increment
1746 if (index != NULL && comparator != EOpNull && node->getTerminal())
1747 {
1748 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1749 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1750
1751 if (binaryTerminal)
1752 {
1753 TOperator op = binaryTerminal->getOp();
1754 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1755
1756 if (constant)
1757 {
1758 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1759 {
1760 int value = constant->getUnionArrayPointer()[0].getIConst();
1761
1762 switch (op)
1763 {
1764 case EOpAddAssign: increment = value; break;
1765 case EOpSubAssign: increment = -value; break;
1766 default: UNIMPLEMENTED();
1767 }
1768 }
1769 }
1770 }
1771 else if (unaryTerminal)
1772 {
1773 TOperator op = unaryTerminal->getOp();
1774
1775 switch (op)
1776 {
1777 case EOpPostIncrement: increment = 1; break;
1778 case EOpPostDecrement: increment = -1; break;
1779 case EOpPreIncrement: increment = 1; break;
1780 case EOpPreDecrement: increment = -1; break;
1781 default: UNIMPLEMENTED();
1782 }
1783 }
1784 }
1785
1786 if (index != NULL && comparator != EOpNull && increment != 0)
1787 {
1788 if (comparator == EOpLessThanEqual)
1789 {
1790 comparator = EOpLessThan;
1791 limit += 1;
1792 }
1793
1794 if (comparator == EOpLessThan)
1795 {
1796 int iterations = (limit - initial + 1) / increment;
1797
1798 if (iterations <= 255)
1799 {
1800 return false; // Not an excessive loop
1801 }
1802
1803 while (iterations > 0)
1804 {
1805 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001806 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001807
1808 // for(int index = initial; index < clampedLimit; index += increment)
1809
1810 out << "for(int ";
1811 index->traverse(this);
1812 out << " = ";
1813 out << initial;
1814
1815 out << "; ";
1816 index->traverse(this);
1817 out << " < ";
1818 out << clampedLimit;
1819
1820 out << "; ";
1821 index->traverse(this);
1822 out << " += ";
1823 out << increment;
1824 out << ")\n"
1825 "{\n";
1826
1827 if (node->getBody())
1828 {
1829 node->getBody()->traverse(this);
1830 }
1831
1832 out << "}\n";
1833
1834 initial += 255 * increment;
1835 iterations -= 255;
1836 }
1837
1838 return true;
1839 }
1840 else UNIMPLEMENTED();
1841 }
1842
1843 return false; // Not handled as an excessive loop
1844}
1845
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001846void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001847{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001848 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001849
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001850 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001851 {
1852 out << preString;
1853 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001854 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001855 {
1856 out << inString;
1857 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001858 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859 {
1860 out << postString;
1861 }
1862}
1863
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001864TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1865{
1866 TQualifier qualifier = symbol->getQualifier();
1867 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001868 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001869
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001870 if (name.empty()) // HLSL demands named arguments, also for prototypes
1871 {
1872 name = "x" + str(mArgumentIndex++);
1873 }
1874 else
1875 {
1876 name = decorate(name);
1877 }
1878
1879 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001880}
1881
1882TString OutputHLSL::qualifierString(TQualifier qualifier)
1883{
1884 switch(qualifier)
1885 {
1886 case EvqIn: return "in";
1887 case EvqOut: return "out";
1888 case EvqInOut: return "inout";
1889 case EvqConstReadOnly: return "const";
1890 default: UNREACHABLE();
1891 }
1892
1893 return "";
1894}
1895
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001896TString OutputHLSL::typeString(const TType &type)
1897{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001898 if (type.getBasicType() == EbtStruct)
1899 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001900 if (type.getTypeName() != "")
1901 {
1902 return decorate(type.getTypeName());
1903 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001904 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001905 {
1906 const TTypeList &fields = *type.getStruct();
1907
1908 TString string = "struct\n"
1909 "{\n";
1910
1911 for (unsigned int i = 0; i < fields.size(); i++)
1912 {
1913 const TType &field = *fields[i].type;
1914
1915 string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1916 }
1917
1918 string += "} ";
1919
1920 return string;
1921 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001922 }
1923 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001924 {
1925 switch (type.getNominalSize())
1926 {
1927 case 2: return "float2x2";
1928 case 3: return "float3x3";
1929 case 4: return "float4x4";
1930 }
1931 }
1932 else
1933 {
1934 switch (type.getBasicType())
1935 {
1936 case EbtFloat:
1937 switch (type.getNominalSize())
1938 {
1939 case 1: return "float";
1940 case 2: return "float2";
1941 case 3: return "float3";
1942 case 4: return "float4";
1943 }
1944 case EbtInt:
1945 switch (type.getNominalSize())
1946 {
1947 case 1: return "int";
1948 case 2: return "int2";
1949 case 3: return "int3";
1950 case 4: return "int4";
1951 }
1952 case EbtBool:
1953 switch (type.getNominalSize())
1954 {
1955 case 1: return "bool";
1956 case 2: return "bool2";
1957 case 3: return "bool3";
1958 case 4: return "bool4";
1959 }
1960 case EbtVoid:
1961 return "void";
1962 case EbtSampler2D:
1963 return "sampler2D";
1964 case EbtSamplerCube:
1965 return "samplerCUBE";
1966 }
1967 }
1968
1969 UNIMPLEMENTED(); // FIXME
1970 return "<unknown type>";
1971}
1972
1973TString OutputHLSL::arrayString(const TType &type)
1974{
1975 if (!type.isArray())
1976 {
1977 return "";
1978 }
1979
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001980 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001981}
1982
1983TString OutputHLSL::initializer(const TType &type)
1984{
1985 TString string;
1986
daniel@transgaming.comead23042010-04-29 03:35:36 +00001987 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001988 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001989 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001990
daniel@transgaming.comead23042010-04-29 03:35:36 +00001991 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001992 {
1993 string += ", ";
1994 }
1995 }
1996
daniel@transgaming.comead23042010-04-29 03:35:36 +00001997 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001998}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001999
daniel@transgaming.com63691862010-04-29 03:32:42 +00002000bool OutputHLSL::CompareConstructor::operator()(const Constructor &x, const Constructor &y) const
2001{
daniel@transgaming.com63691862010-04-29 03:32:42 +00002002 if (x.name != y.name)
2003 {
2004 return x.name < y.name;
2005 }
2006
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002007 if (x.type != y.type)
2008 {
2009 return memcmp(&x.type, &y.type, sizeof(TType)) < 0;
2010 }
2011
daniel@transgaming.com63691862010-04-29 03:32:42 +00002012 if (x.parameters.size() != y.parameters.size())
2013 {
2014 return x.parameters.size() < y.parameters.size();
2015 }
2016
2017 for (unsigned int i = 0; i < x.parameters.size(); i++)
2018 {
2019 if (x.parameters[i] != y.parameters[i])
2020 {
2021 return memcmp(&x.parameters[i], &y.parameters[i], sizeof(TType)) < 0;
2022 }
2023 }
2024
2025 return false;
2026}
2027
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002028void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00002029{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002030 if (name == "")
2031 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00002032 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002033 }
2034
daniel@transgaming.com63691862010-04-29 03:32:42 +00002035 Constructor constructor;
2036
2037 constructor.type = type;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00002038 constructor.type.clearArrayness();
2039 constructor.type.changePrecision(EbpHigh);
2040 constructor.type.changeQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00002041 constructor.name = name;
2042
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002043 if (parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00002044 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002045 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2046 {
2047 constructor.parameters.push_back((*parameter)->getAsTyped()->getType());
2048 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00002049 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002050 else if (type.getStruct())
2051 {
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00002052 if (std::find(mStructures.begin(), mStructures.end(), constructor.type) == mStructures.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002053 {
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +00002054 mStructures.push_back(constructor.type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002055 }
2056
2057 const TTypeList *structure = type.getStruct();
2058
2059 for (unsigned int i = 0; i < structure->size(); i++)
2060 {
2061 constructor.parameters.push_back(*(*structure)[i].type);
2062 }
2063 }
2064 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00002065
2066 mConstructors.insert(constructor);
2067}
2068
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002069const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2070{
2071 TInfoSinkBase &out = mBody;
2072
2073 if (type.getBasicType() == EbtStruct)
2074 {
2075 out << type.getTypeName() + "_ctor(";
2076
2077 const TTypeList *structure = type.getStruct();
2078
2079 for (size_t i = 0; i < structure->size(); i++)
2080 {
2081 const TType *fieldType = (*structure)[i].type;
2082
2083 constUnion = writeConstantUnion(*fieldType, constUnion);
2084
2085 if (i != structure->size() - 1)
2086 {
2087 out << ", ";
2088 }
2089 }
2090
2091 out << ")";
2092 }
2093 else
2094 {
2095 int size = type.getObjectSize();
2096 bool writeType = size > 1;
2097
2098 if (writeType)
2099 {
2100 out << typeString(type) << "(";
2101 }
2102
2103 for (int i = 0; i < size; i++, constUnion++)
2104 {
2105 switch (constUnion->getType())
2106 {
2107 case EbtFloat: out << constUnion->getFConst(); break;
2108 case EbtInt: out << constUnion->getIConst(); break;
2109 case EbtBool:
2110 if (constUnion->getBConst())
2111 {
2112 out << "true";
2113 }
2114 else
2115 {
2116 out << "false";
2117 }
2118 break;
2119 default: UNREACHABLE();
2120 }
2121
2122 if (i != size - 1)
2123 {
2124 out << ", ";
2125 }
2126 }
2127
2128 if (writeType)
2129 {
2130 out << ")";
2131 }
2132 }
2133
2134 return constUnion;
2135}
2136
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002137TString OutputHLSL::decorate(const TString &string)
2138{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002139 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002140 {
2141 return "_" + string;
2142 }
2143 else
2144 {
2145 return string;
2146 }
2147}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002148}