blob: 109b356cdbf79ad0b3fe8a33d39842e2ff32ef77 [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
14namespace sh
15{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000016// Integer to TString conversion
17TString str(int i)
18{
19 char buffer[20];
20 sprintf(buffer, "%d", i);
21 return buffer;
22}
23
daniel@transgaming.com950f9932010-04-13 03:26:14 +000024OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000026 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000027 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000028
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000029 mUsesTexture2D = false;
30 mUsesTexture2D_bias = false;
31 mUsesTexture2DProj = false;
32 mUsesTexture2DProj_bias = false;
33 mUsesTextureCube = false;
34 mUsesTextureCube_bias = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000035 mUsesEqualMat2 = false;
36 mUsesEqualMat3 = false;
37 mUsesEqualMat4 = false;
38 mUsesEqualVec2 = false;
39 mUsesEqualVec3 = false;
40 mUsesEqualVec4 = false;
41 mUsesEqualIVec2 = false;
42 mUsesEqualIVec3 = false;
43 mUsesEqualIVec4 = false;
44 mUsesEqualBVec2 = false;
45 mUsesEqualBVec3 = false;
46 mUsesEqualBVec4 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000047
48 mArgumentIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049}
50
daniel@transgaming.comb5875982010-04-15 20:44:53 +000051OutputHLSL::~OutputHLSL()
52{
53 delete mUnfoldSelect;
54}
55
daniel@transgaming.com950f9932010-04-13 03:26:14 +000056void OutputHLSL::output()
57{
58 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
59 header();
60 footer();
61
62 mContext.infoSink.obj << mHeader.c_str();
63 mContext.infoSink.obj << mBody.c_str();
64 mContext.infoSink.obj << mFooter.c_str();
65}
66
daniel@transgaming.comb5875982010-04-15 20:44:53 +000067TInfoSinkBase &OutputHLSL::getBodyStream()
68{
69 return mBody;
70}
71
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000072void OutputHLSL::header()
73{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000074 EShLanguage language = mContext.language;
75 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076
77 if (language == EShLangFragment)
78 {
79 TString uniforms;
80 TString varyingInput;
81 TString varyingGlobals;
82
daniel@transgaming.com950f9932010-04-13 03:26:14 +000083 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000084 int semanticIndex = 0;
85
86 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
87 {
88 const TSymbol *symbol = (*namedSymbol).second;
89 const TString &name = symbol->getName();
90
91 if (symbol->isVariable())
92 {
93 const TVariable *variable = static_cast<const TVariable*>(symbol);
94 const TType &type = variable->getType();
95 TQualifier qualifier = type.getQualifier();
96
97 if (qualifier == EvqUniform)
98 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +000099 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
100 {
101 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
102 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000103 }
104 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
105 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000106 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
107 {
108 // Program linking depends on this exact format
109 varyingInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
110 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000111
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000112 semanticIndex += type.isArray() ? type.getArraySize() : 1;
113 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000115 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000116 {
117 // Globals are declared and intialized as an aggregate node
118 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000119 else if (qualifier == EvqConst)
120 {
121 // Constants are repeated as literals where used
122 }
123 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124 }
125 }
126
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000127 out << "uniform float4 gl_Window;\n"
128 "uniform float2 gl_Depth;\n"
daniel@transgaming.com5af64272010-04-15 20:45:12 +0000129 "uniform bool gl_PointsOrLines;\n"
130 "uniform bool gl_FrontCCW;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000131 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132 out << uniforms;
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000133 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000134 "struct PS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 "{\n";
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000136 out << varyingInput;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000137 out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000138 out << " float vFace : VFACE;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000139 "};\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140 "\n";
141 out << varyingGlobals;
142 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000143 "struct PS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 "{\n"
145 " float4 gl_Color[1] : COLOR;\n"
146 "};\n"
147 "\n"
148 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000149 "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000150 "static float2 gl_PointCoord = float2(0.5, 0.5);\n"
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000151 "static bool gl_FrontFacing = false;\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152 "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000153
154 if (mUsesTexture2D)
155 {
156 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
157 "{\n"
158 " return tex2D(s, t);\n"
159 "}\n"
160 "\n";
161 }
162
163 if (mUsesTexture2D_bias)
164 {
165 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
166 "{\n"
167 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
168 "}\n"
169 "\n";
170 }
171
172 if (mUsesTexture2DProj)
173 {
174 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
175 "{\n"
176 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
177 "}\n"
178 "\n"
179 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
180 "{\n"
181 " return tex2Dproj(s, t);\n"
182 "}\n"
183 "\n";
184 }
185
186 if (mUsesTexture2DProj_bias)
187 {
188 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
189 "{\n"
190 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
191 "}\n"
192 "\n"
193 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
194 "{\n"
195 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
196 "}\n"
197 "\n";
198 }
199
200 if (mUsesTextureCube)
201 {
202 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
203 "{\n"
204 " return texCUBE(s, t);\n"
205 "}\n"
206 "\n";
207 }
208
209 if (mUsesTextureCube_bias)
210 {
211 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
212 "{\n"
213 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
214 "}\n"
215 "\n";
216 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000218 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219 {
220 TString uniforms;
221 TString attributeInput;
222 TString attributeGlobals;
223 TString varyingOutput;
224 TString varyingGlobals;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000226 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227 int semanticIndex = 0;
228
229 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
230 {
231 const TSymbol *symbol = (*namedSymbol).second;
232 const TString &name = symbol->getName();
233
234 if (symbol->isVariable())
235 {
236 const TVariable *variable = static_cast<const TVariable*>(symbol);
237 const TType &type = variable->getType();
238 TQualifier qualifier = type.getQualifier();
239
240 if (qualifier == EvqUniform)
241 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000242 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
243 {
244 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
245 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000246 }
247 else if (qualifier == EvqAttribute)
248 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000249 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
250 {
251 attributeInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
252 attributeGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000253
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000254 semanticIndex += type.isArray() ? type.getArraySize() : 1;
255 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256 }
257 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
258 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000259 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
260 {
261 // Program linking depends on this exact format
262 varyingOutput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
263 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
264 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000266 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000268 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000270 else if (qualifier == EvqConst)
271 {
272 // Constants are repeated as literals where used
273 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274 else UNREACHABLE();
275 }
276 }
277
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000278 out << "uniform float2 gl_HalfPixelSize;\n"
279 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280 out << uniforms;
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000281 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000282 "struct VS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283 "{\n";
284 out << attributeInput;
285 out << "};\n"
286 "\n";
287 out << attributeGlobals;
288 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000289 "struct VS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 "{\n"
291 " float4 gl_Position : POSITION;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000292 " float gl_PointSize : PSIZE;\n"
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000293 " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000294 out << varyingOutput;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295 out << "};\n"
296 "\n"
297 "static float4 gl_Position = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000298 "static float gl_PointSize = float(1);\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 out << varyingGlobals;
300 out << "\n";
301 }
302
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000303 out << "struct gl_DepthRangeParameters\n"
304 "{\n"
305 " float near;\n"
306 " float far;\n"
307 " float diff;\n"
308 "};\n"
309 "\n"
310 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
311 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000312 "float vec1(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 "{\n"
314 " return x;\n"
315 "}\n"
316 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000317 "float vec1(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318 "{\n"
319 " return xy[0];\n"
320 "}\n"
321 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000322 "float vec1(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 "{\n"
324 " return xyz[0];\n"
325 "}\n"
326 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000327 "float vec1(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 "{\n"
329 " return xyzw[0];\n"
330 "}\n"
331 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000332 "float2 vec2(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333 "{\n"
334 " return float2(x, x);\n"
335 "}\n"
336 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000337 "float2 vec2(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338 "{\n"
339 " return float2(x, y);\n"
340 "}\n"
341 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000342 "float2 vec2(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343 "{\n"
344 " return xy;\n"
345 "}\n"
346 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000347 "float2 vec2(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 "{\n"
349 " return float2(xyz[0], xyz[1]);\n"
350 "}\n"
351 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000352 "float2 vec2(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353 "{\n"
354 " return float2(xyzw[0], xyzw[1]);\n"
355 "}\n"
356 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000357 "float3 vec3(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358 "{\n"
359 " return float3(x, x, x);\n"
360 "}\n"
361 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000362 "float3 vec3(float x, float y, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000363 "{\n"
364 " return float3(x, y, z);\n"
365 "}\n"
366 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000367 "float3 vec3(float2 xy, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 "{\n"
369 " return float3(xy[0], xy[1], z);\n"
370 "}\n"
371 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000372 "float3 vec3(float x, float2 yz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373 "{\n"
374 " return float3(x, yz[0], yz[1]);\n"
375 "}\n"
376 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000377 "float3 vec3(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000378 "{\n"
379 " return xyz;\n"
380 "}\n"
381 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000382 "float3 vec3(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383 "{\n"
384 " return float3(xyzw[0], xyzw[1], xyzw[2]);\n"
385 "}\n"
386 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000387 "float4 vec4(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388 "{\n"
389 " return float4(x, x, x, x);\n"
390 "}\n"
391 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000392 "float4 vec4(float x, float y, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000393 "{\n"
394 " return float4(x, y, z, w);\n"
395 "}\n"
396 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000397 "float4 vec4(float2 xy, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398 "{\n"
399 " return float4(xy[0], xy[1], z, w);\n"
400 "}\n"
401 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000402 "float4 vec4(float x, float2 yz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403 "{\n"
404 " return float4(x, yz[0], yz[1], w);\n"
405 "}\n"
406 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000407 "float4 vec4(float x, float y, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000408 "{\n"
409 " return float4(x, y, zw[0], zw[1]);\n"
410 "}\n"
411 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000412 "float4 vec4(float2 xy, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 "{\n"
414 " return float4(xy[0], xy[1], zw[0], zw[1]);\n"
415 "}\n"
416 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000417 "float4 vec4(float3 xyz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 "{\n"
419 " return float4(xyz[0], xyz[1], xyz[2], w);\n"
420 "}\n"
421 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000422 "float4 vec4(float x, float3 yzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000423 "{\n"
424 " return float4(x, yzw[0], yzw[1], yzw[2]);\n"
425 "}\n"
426 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000427 "float4 vec4(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 "{\n"
429 " return xyzw;\n"
430 "}\n"
431 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000432 "bool xor(bool p, bool q)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433 "{\n"
434 " return (p || q) && !(p && q);\n"
435 "}\n"
436 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000437 "float mod(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 "{\n"
439 " return x - y * floor(x / y);\n"
440 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000441 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000442 "float2 mod(float2 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 "{\n"
444 " return x - y * floor(x / y);\n"
445 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000446 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000447 "float3 mod(float3 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 "{\n"
449 " return x - y * floor(x / y);\n"
450 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000451 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000452 "float4 mod(float4 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 "{\n"
454 " return x - y * floor(x / y);\n"
455 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000456 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000457 "float faceforward(float N, float I, float Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000458 "{\n"
459 " if(dot(Nref, I) < 0)\n"
460 " {\n"
461 " return N;\n"
462 " }\n"
463 " else\n"
464 " {\n"
465 " return -N;\n"
466 " }\n"
467 "}\n"
468 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000469 "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000470 "{\n"
471 " if(dot(Nref, I) < 0)\n"
472 " {\n"
473 " return N;\n"
474 " }\n"
475 " else\n"
476 " {\n"
477 " return -N;\n"
478 " }\n"
479 "}\n"
480 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000481 "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000482 "{\n"
483 " if(dot(Nref, I) < 0)\n"
484 " {\n"
485 " return N;\n"
486 " }\n"
487 " else\n"
488 " {\n"
489 " return -N;\n"
490 " }\n"
491 "}\n"
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000492 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000493 "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000494 "{\n"
495 " if(dot(Nref, I) < 0)\n"
496 " {\n"
497 " return N;\n"
498 " }\n"
499 " else\n"
500 " {\n"
501 " return -N;\n"
502 " }\n"
503 "}\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504 "\n";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000505
506 if (mUsesEqualMat2)
507 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000508 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000509 "{\n"
510 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
511 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
512 "}\n";
513 }
514
515 if (mUsesEqualMat3)
516 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000517 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000518 "{\n"
519 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
520 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
521 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
522 "}\n";
523 }
524
525 if (mUsesEqualMat4)
526 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000527 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000528 "{\n"
529 " 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"
530 " 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"
531 " 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"
532 " 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"
533 "}\n";
534 }
535
536 if (mUsesEqualVec2)
537 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000538 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000539 "{\n"
540 " return v.x == u.x && v.y == u.y;\n"
541 "}\n";
542 }
543
544 if (mUsesEqualVec3)
545 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000546 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000547 "{\n"
548 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
549 "}\n";
550 }
551
552 if (mUsesEqualVec4)
553 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000554 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000555 "{\n"
556 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
557 "}\n";
558 }
559
560 if (mUsesEqualIVec2)
561 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000562 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000563 "{\n"
564 " return v.x == u.x && v.y == u.y;\n"
565 "}\n";
566 }
567
568 if (mUsesEqualIVec3)
569 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000570 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000571 "{\n"
572 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
573 "}\n";
574 }
575
576 if (mUsesEqualIVec4)
577 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000578 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000579 "{\n"
580 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
581 "}\n";
582 }
583
584 if (mUsesEqualBVec2)
585 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000586 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000587 "{\n"
588 " return v.x == u.x && v.y == u.y;\n"
589 "}\n";
590 }
591
592 if (mUsesEqualBVec3)
593 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000594 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000595 "{\n"
596 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
597 "}\n";
598 }
599
600 if (mUsesEqualBVec4)
601 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000602 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000603 "{\n"
604 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
605 "}\n";
606 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000607}
608
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000609void OutputHLSL::footer()
610{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000611 EShLanguage language = mContext.language;
612 TInfoSinkBase &out = mFooter;
613 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000614
615 if (language == EShLangFragment)
616 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000617 out << "PS_OUTPUT main(PS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000618 "{\n"
619 " float rhw = 1.0 / input.gl_FragCoord.w;\n"
620 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * gl_Window.x + gl_Window.z;\n"
621 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * gl_Window.y + gl_Window.w;\n"
622 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * gl_Depth.x + gl_Depth.y;\n"
623 " gl_FragCoord.w = rhw;\n"
daniel@transgaming.com5af64272010-04-15 20:45:12 +0000624 " gl_FrontFacing = gl_PointsOrLines || (gl_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000625
626 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
627 {
628 const TSymbol *symbol = (*namedSymbol).second;
629 const TString &name = symbol->getName();
630
631 if (symbol->isVariable())
632 {
633 const TVariable *variable = static_cast<const TVariable*>(symbol);
634 const TType &type = variable->getType();
635 TQualifier qualifier = type.getQualifier();
636
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000637 if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000638 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000639 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
640 {
641 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
642 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000643 }
644 }
645 }
646
647 out << "\n"
648 " gl_main();\n"
649 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000650 " PS_OUTPUT output;\n"
651 " output.gl_Color[0] = gl_Color[0];\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000652 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000653 else // Vertex shader
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000654 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000655 out << "VS_OUTPUT main(VS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000656 "{\n";
657
658 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
659 {
660 const TSymbol *symbol = (*namedSymbol).second;
661 const TString &name = symbol->getName();
662
663 if (symbol->isVariable())
664 {
665 const TVariable *variable = static_cast<const TVariable*>(symbol);
666 const TType &type = variable->getType();
667 TQualifier qualifier = type.getQualifier();
668
669 if (qualifier == EvqAttribute)
670 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000671 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
672 {
673 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
674 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000675 }
676 }
677 }
678
679 out << "\n"
680 " gl_main();\n"
681 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000682 " VS_OUTPUT output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000683 " output.gl_Position.x = gl_Position.x - gl_HalfPixelSize.x * gl_Position.w;\n"
684 " output.gl_Position.y = -(gl_Position.y - gl_HalfPixelSize.y * gl_Position.w);\n"
685 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
686 " output.gl_Position.w = gl_Position.w;\n"
687 " output.gl_PointSize = gl_PointSize;\n"
688 " output.gl_FragCoord = gl_Position;\n";
689
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000690 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000691
692 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
693 {
694 const TSymbol *symbol = (*namedSymbol).second;
695 const TString &name = symbol->getName();
696
697 if (symbol->isVariable())
698 {
699 const TVariable *variable = static_cast<const TVariable*>(symbol);
700 TQualifier qualifier = variable->getType().getQualifier();
701
702 if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
703 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000704 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
705 {
706 // Program linking depends on this exact format
707 out << " output." + decorate(name) + " = " + decorate(name) + ";\n";
708 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000709 }
710 }
711 }
712 }
713
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000714 out << " return output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000715 "}\n";
716}
717
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718void OutputHLSL::visitSymbol(TIntermSymbol *node)
719{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000720 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000721
722 TString name = node->getSymbol();
723
724 if (name == "gl_FragColor")
725 {
726 out << "gl_Color[0]";
727 }
728 else if (name == "gl_FragData")
729 {
730 out << "gl_Color";
731 }
732 else
733 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000734 TQualifier qualifier = node->getQualifier();
735
736 if (qualifier == EvqUniform)
737 {
738 mReferencedUniforms.insert(name.c_str());
739 }
740 else if (qualifier == EvqAttribute)
741 {
742 mReferencedAttributes.insert(name.c_str());
743 }
744 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
745 {
746 mReferencedVaryings.insert(name.c_str());
747 }
748
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000749 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000750 }
751}
752
753bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
754{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000755 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756
757 switch (node->getOp())
758 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000759 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
760 case EOpInitialize: outputTriplet(visit, NULL, " = ", NULL); break;
761 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
762 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
763 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
764 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
765 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
766 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000767 if (visit == PreVisit)
768 {
769 out << "(";
770 }
771 else if (visit == InVisit)
772 {
773 out << " = mul(";
774 node->getLeft()->traverse(this);
775 out << ", transpose(";
776 }
777 else
778 {
779 out << "))";
780 }
781 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000782 case EOpMatrixTimesMatrixAssign:
783 if (visit == PreVisit)
784 {
785 out << "(";
786 }
787 else if (visit == InVisit)
788 {
789 out << " = mul(";
790 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000791 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000792 }
793 else
794 {
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000795 out << ")";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000796 }
797 break;
798 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
799 case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break;
800 case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break;
801 case EOpIndexDirectStruct: outputTriplet(visit, NULL, ".", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000802 case EOpVectorSwizzle:
803 if (visit == InVisit)
804 {
805 out << ".";
806
807 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
808
809 if (swizzle)
810 {
811 TIntermSequence &sequence = swizzle->getSequence();
812
813 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
814 {
815 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
816
817 if (element)
818 {
819 int i = element->getUnionArrayPointer()[0].getIConst();
820
821 switch (i)
822 {
823 case 0: out << "x"; break;
824 case 1: out << "y"; break;
825 case 2: out << "z"; break;
826 case 3: out << "w"; break;
827 default: UNREACHABLE();
828 }
829 }
830 else UNREACHABLE();
831 }
832 }
833 else UNREACHABLE();
834
835 return false; // Fully processed
836 }
837 break;
838 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
839 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
840 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
841 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000842 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000843 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000844 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000845 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000846 if (node->getOp() == EOpEqual)
847 {
848 outputTriplet(visit, "(", " == ", ")");
849 }
850 else
851 {
852 outputTriplet(visit, "(", " != ", ")");
853 }
854 }
855 else if (node->getLeft()->getBasicType() == EbtStruct)
856 {
857 if (node->getOp() == EOpEqual)
858 {
859 out << "(";
860 }
861 else
862 {
863 out << "!(";
864 }
865
866 const TTypeList *fields = node->getLeft()->getType().getStruct();
867
868 for (size_t i = 0; i < fields->size(); i++)
869 {
870 const TType *fieldType = (*fields)[i].type;
871
872 node->getLeft()->traverse(this);
873 out << "." + fieldType->getFieldName() + " == ";
874 node->getRight()->traverse(this);
875 out << "." + fieldType->getFieldName();
876
877 if (i < fields->size() - 1)
878 {
879 out << " && ";
880 }
881 }
882
883 out << ")";
884
885 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000886 }
887 else
888 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000889 if (node->getLeft()->isMatrix())
890 {
891 switch (node->getLeft()->getSize())
892 {
893 case 2 * 2: mUsesEqualMat2 = true; break;
894 case 3 * 3: mUsesEqualMat3 = true; break;
895 case 4 * 4: mUsesEqualMat4 = true; break;
896 default: UNREACHABLE();
897 }
898 }
899 else if (node->getLeft()->isVector())
900 {
901 switch (node->getLeft()->getBasicType())
902 {
903 case EbtFloat:
904 switch (node->getLeft()->getSize())
905 {
906 case 2: mUsesEqualVec2 = true; break;
907 case 3: mUsesEqualVec3 = true; break;
908 case 4: mUsesEqualVec4 = true; break;
909 default: UNREACHABLE();
910 }
911 break;
912 case EbtInt:
913 switch (node->getLeft()->getSize())
914 {
915 case 2: mUsesEqualIVec2 = true; break;
916 case 3: mUsesEqualIVec3 = true; break;
917 case 4: mUsesEqualIVec4 = true; break;
918 default: UNREACHABLE();
919 }
920 break;
921 case EbtBool:
922 switch (node->getLeft()->getSize())
923 {
924 case 2: mUsesEqualBVec2 = true; break;
925 case 3: mUsesEqualBVec3 = true; break;
926 case 4: mUsesEqualBVec4 = true; break;
927 default: UNREACHABLE();
928 }
929 break;
930 default: UNREACHABLE();
931 }
932 }
933 else UNREACHABLE();
934
935 if (node->getOp() == EOpEqual)
936 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000937 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000938 }
939 else
940 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000941 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000942 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000943 }
944 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
946 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
947 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
948 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
949 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000950 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000951 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
952 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
953 case EOpMatrixTimesMatrix: outputTriplet(visit, "mul(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000955 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000956 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
957 default: UNREACHABLE();
958 }
959
960 return true;
961}
962
963bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
964{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000965 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966
967 switch (node->getOp())
968 {
969 case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break;
970 case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
971 case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000972 case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break;
973 case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break;
974 case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break;
975 case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break;
976 case EOpConvIntToBool:
977 case EOpConvFloatToBool:
978 switch (node->getOperand()->getType().getNominalSize())
979 {
980 case 1: outputTriplet(visit, "bool(", NULL, ")"); break;
981 case 2: outputTriplet(visit, "bool2(", NULL, ")"); break;
982 case 3: outputTriplet(visit, "bool3(", NULL, ")"); break;
983 case 4: outputTriplet(visit, "bool4(", NULL, ")"); break;
984 default: UNREACHABLE();
985 }
986 break;
987 case EOpConvBoolToFloat:
988 case EOpConvIntToFloat:
989 switch (node->getOperand()->getType().getNominalSize())
990 {
991 case 1: outputTriplet(visit, "float(", NULL, ")"); break;
992 case 2: outputTriplet(visit, "float2(", NULL, ")"); break;
993 case 3: outputTriplet(visit, "float3(", NULL, ")"); break;
994 case 4: outputTriplet(visit, "float4(", NULL, ")"); break;
995 default: UNREACHABLE();
996 }
997 break;
998 case EOpConvFloatToInt:
999 case EOpConvBoolToInt:
1000 switch (node->getOperand()->getType().getNominalSize())
1001 {
1002 case 1: outputTriplet(visit, "int(", NULL, ")"); break;
1003 case 2: outputTriplet(visit, "int2(", NULL, ")"); break;
1004 case 3: outputTriplet(visit, "int3(", NULL, ")"); break;
1005 case 4: outputTriplet(visit, "int4(", NULL, ")"); break;
1006 default: UNREACHABLE();
1007 }
1008 break;
1009 case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break;
1010 case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break;
1011 case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break;
1012 case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break;
1013 case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break;
1014 case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break;
1015 case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break;
1016 case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break;
1017 case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break;
1018 case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break;
1019 case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break;
1020 case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break;
1021 case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break;
1022 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break;
1023 case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break;
1024 case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break;
1025 case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break;
1026 case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break;
1027 case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break;
1028 case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break;
1029 case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break;
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001030// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break;
1031// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break;
1032// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001033 case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break;
1034 case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break;
1035 default: UNREACHABLE();
1036 }
1037
1038 return true;
1039}
1040
1041bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1042{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001043 EShLanguage language = mContext.language;
1044 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 switch (node->getOp())
1047 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001048 case EOpSequence:
1049 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001050 if (mInsideFunction)
1051 {
1052 out << "{\n";
1053 }
1054
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001055 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1056 {
1057 if (isSingleStatement(*sit))
1058 {
1059 mUnfoldSelect->traverse(*sit);
1060 }
1061
1062 (*sit)->traverse(this);
1063
1064 out << ";\n";
1065 }
1066
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001067 if (mInsideFunction)
1068 {
1069 out << "}\n";
1070 }
1071
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001072 return false;
1073 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 case EOpDeclaration:
1075 if (visit == PreVisit)
1076 {
1077 TIntermSequence &sequence = node->getSequence();
1078 TIntermTyped *variable = sequence[0]->getAsTyped();
1079 bool visit = true;
1080
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001081 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001083 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001085 if (variable->getQualifier() == EvqGlobal)
1086 {
1087 out << "static ";
1088 }
1089
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001090 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001091
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001092 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001093 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001094 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001095
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001096 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001097 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001098 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001099 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001100 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001101 }
1102 else
1103 {
1104 (*sit)->traverse(this);
1105 }
1106
1107 if (visit && this->inVisit)
1108 {
1109 if (*sit != sequence.back())
1110 {
1111 visit = this->visitAggregate(InVisit, node);
1112 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001113 }
1114 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001116 if (visit && this->postVisit)
1117 {
1118 this->visitAggregate(PostVisit, node);
1119 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001120 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001121 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1122 {
1123 const TType &type = variable->getType();
1124 const TTypeList &fields = *type.getStruct();
1125
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001126 out << "struct " + decorate(type.getTypeName()) + "\n"
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001127 "{\n";
1128
1129 for (unsigned int i = 0; i < fields.size(); i++)
1130 {
1131 const TType &field = *fields[i].type;
1132
1133 out << " " + typeString(field) + " " + field.getFieldName() + ";\n";
1134 }
1135
1136 out << "};\n";
1137 }
1138 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139 }
1140
1141 return false;
1142 }
1143 else if (visit == InVisit)
1144 {
1145 out << ", ";
1146 }
1147 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001148 case EOpPrototype:
1149 if (visit == PreVisit)
1150 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001151 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001152
1153 TIntermSequence &arguments = node->getSequence();
1154
1155 for (unsigned int i = 0; i < arguments.size(); i++)
1156 {
1157 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1158
1159 if (symbol)
1160 {
1161 out << argumentString(symbol);
1162
1163 if (i < arguments.size() - 1)
1164 {
1165 out << ", ";
1166 }
1167 }
1168 else UNREACHABLE();
1169 }
1170
1171 out << ");\n";
1172
1173 return false;
1174 }
1175 break;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001176 case EOpComma: outputTriplet(visit, NULL, ", ", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001177 case EOpFunction:
1178 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001179 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001180
1181 if (visit == PreVisit)
1182 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001183 out << typeString(node->getType()) << " ";
1184
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185 if (name == "main")
1186 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001187 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001188 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001189 else
1190 {
1191 out << decorate(name) << "(";
1192 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001193
1194 TIntermSequence &sequence = node->getSequence();
1195 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1196
1197 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001198 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001199 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001200
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001201 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001202 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001203 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001204
1205 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001206 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001207 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001210 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001212
1213 sequence.erase(sequence.begin());
1214
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001215 out << ")\n";
1216
1217 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218 }
1219 else if (visit == PostVisit)
1220 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001221 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001222 }
1223 }
1224 break;
1225 case EOpFunctionCall:
1226 {
1227 if (visit == PreVisit)
1228 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001229 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230
1231 if (node->isUserDefined())
1232 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001233 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001234 }
1235 else
1236 {
1237 if (name == "texture2D")
1238 {
1239 if (node->getSequence().size() == 2)
1240 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001241 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242 }
1243 else if (node->getSequence().size() == 3)
1244 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001245 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001246 }
1247 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001248
1249 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250 }
1251 else if (name == "texture2DProj")
1252 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001253 if (node->getSequence().size() == 2)
1254 {
1255 mUsesTexture2DProj = true;
1256 }
1257 else if (node->getSequence().size() == 3)
1258 {
1259 mUsesTexture2DProj_bias = true;
1260 }
1261 else UNREACHABLE();
1262
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001263 out << "gl_texture2DProj(";
1264 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001265 else if (name == "textureCube")
1266 {
1267 if (node->getSequence().size() == 2)
1268 {
1269 mUsesTextureCube = true;
1270 }
1271 else if (node->getSequence().size() == 3)
1272 {
1273 mUsesTextureCube_bias = true;
1274 }
1275 else UNREACHABLE();
1276
1277 out << "gl_textureCube(";
1278 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001279 else if (name == "texture2DLod")
1280 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001281 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001282 }
1283 else if (name == "texture2DProjLod")
1284 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001285 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001286 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001287 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001288 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001289 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001290 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001291 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001292 }
1293 }
1294 else if (visit == InVisit)
1295 {
1296 out << ", ";
1297 }
1298 else
1299 {
1300 out << ")";
1301 }
1302 }
1303 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001304 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1305 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1306 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1307 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1308 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001309 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1310 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1311 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1312 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1313 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1314 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1315 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1316 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001317 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1318 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1319 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1320 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1321 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1322 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1323 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1324 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1325 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1326 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001327 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001328 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001329 case EOpAtan:
1330 if (node->getSequence().size() == 1)
1331 {
1332 outputTriplet(visit, "atan(", ", ", ")");
1333 }
1334 else if (node->getSequence().size() == 2)
1335 {
1336 outputTriplet(visit, "atan2(", ", ", ")");
1337 }
1338 else UNREACHABLE();
1339 break;
1340 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1341 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1342 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1343 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1344 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1345 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1346 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1347 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1348 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com680553b2010-03-08 21:30:52 +00001349 case EOpFaceForward: outputTriplet(visit, "faceforward(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001350 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1351 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1352 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353 default: UNREACHABLE();
1354 }
1355
1356 return true;
1357}
1358
1359bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1360{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001361 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001362
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001363 if (node->usesTernaryOperator())
1364 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001365 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001366 }
1367 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001368 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001369 mUnfoldSelect->traverse(node->getCondition());
1370
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001371 out << "if(";
1372
1373 node->getCondition()->traverse(this);
1374
1375 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001376 "{\n";
1377
daniel@transgaming.combb885322010-04-15 20:45:24 +00001378 if (node->getTrueBlock())
1379 {
1380 node->getTrueBlock()->traverse(this);
1381 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001382
1383 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001384
1385 if (node->getFalseBlock())
1386 {
1387 out << "else\n"
1388 "{\n";
1389
1390 node->getFalseBlock()->traverse(this);
1391
1392 out << ";}\n";
1393 }
1394 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001395
1396 return false;
1397}
1398
1399void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1400{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001401 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001402
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001403 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001404
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001405 if (type.isField())
1406 {
1407 out << type.getFieldName();
1408 }
1409 else
1410 {
1411 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001412
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001413 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001414 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001415 out << "{";
1416 }
1417 else
1418 {
1419 bool matrix = type.isMatrix();
1420 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1421
1422 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001423 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001424 case EbtBool:
1425 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001426 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001427 switch (size)
1428 {
1429 case 1: out << "bool("; break;
1430 case 2: out << "bool2("; break;
1431 case 3: out << "bool3("; break;
1432 case 4: out << "bool4("; break;
1433 default: UNREACHABLE();
1434 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001435 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001436 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001437 break;
1438 case EbtFloat:
1439 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001440 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001441 switch (size)
1442 {
1443 case 1: out << "float("; break;
1444 case 2: out << "float2("; break;
1445 case 3: out << "float3("; break;
1446 case 4: out << "float4("; break;
1447 default: UNREACHABLE();
1448 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001449 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001450 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001451 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001452 switch (size)
1453 {
1454 case 4: out << "float2x2("; break;
1455 case 9: out << "float3x3("; break;
1456 case 16: out << "float4x4("; break;
1457 default: UNREACHABLE();
1458 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001459 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001460 break;
1461 case EbtInt:
1462 if (!matrix)
1463 {
1464 switch (size)
1465 {
1466 case 1: out << "int("; break;
1467 case 2: out << "int2("; break;
1468 case 3: out << "int3("; break;
1469 case 4: out << "int4("; break;
1470 default: UNREACHABLE();
1471 }
1472 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001473 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001474 break;
1475 default:
1476 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001477 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001478 }
1479
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001480 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001481 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001482 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001483 {
1484 case EbtBool:
1485 if (node->getUnionArrayPointer()[i].getBConst())
1486 {
1487 out << "true";
1488 }
1489 else
1490 {
1491 out << "false";
1492 }
1493 break;
1494 case EbtFloat:
1495 out << node->getUnionArrayPointer()[i].getFConst();
1496 break;
1497 case EbtInt:
1498 out << node->getUnionArrayPointer()[i].getIConst();
1499 break;
1500 default:
1501 UNIMPLEMENTED(); // FIXME
1502 }
1503
1504 if (i != size - 1)
1505 {
1506 out << ", ";
1507 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001508 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001509
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001510 if (type.getBasicType() == EbtStruct)
1511 {
1512 out << "}";
1513 }
1514 else
1515 {
1516 out << ")";
1517 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001519}
1520
1521bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1522{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001523 if (handleExcessiveLoop(node))
1524 {
1525 return false;
1526 }
1527
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001528 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529
1530 if (!node->testFirst())
1531 {
1532 out << "do\n"
1533 "{\n";
1534 }
1535 else
1536 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001537 if (node->getInit())
1538 {
1539 mUnfoldSelect->traverse(node->getInit());
1540 }
1541
1542 if (node->getTest())
1543 {
1544 mUnfoldSelect->traverse(node->getTest());
1545 }
1546
1547 if (node->getTerminal())
1548 {
1549 mUnfoldSelect->traverse(node->getTerminal());
1550 }
1551
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552 out << "for(";
1553
1554 if (node->getInit())
1555 {
1556 node->getInit()->traverse(this);
1557 }
1558
1559 out << "; ";
1560
1561 if (node->getTest())
1562 {
1563 node->getTest()->traverse(this);
1564 }
1565
1566 out << "; ";
1567
1568 if (node->getTerminal())
1569 {
1570 node->getTerminal()->traverse(this);
1571 }
1572
1573 out << ")\n"
1574 "{\n";
1575 }
1576
1577 if (node->getBody())
1578 {
1579 node->getBody()->traverse(this);
1580 }
1581
1582 out << "}\n";
1583
1584 if (!node->testFirst())
1585 {
1586 out << "while(\n";
1587
1588 node->getTest()->traverse(this);
1589
1590 out << ")";
1591 }
1592
1593 out << ";\n";
1594
1595 return false;
1596}
1597
1598bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1599{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001600 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001601
1602 switch (node->getFlowOp())
1603 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001604 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1605 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1606 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607 case EOpReturn:
1608 if (visit == PreVisit)
1609 {
1610 if (node->getExpression())
1611 {
1612 out << "return ";
1613 }
1614 else
1615 {
1616 out << "return;\n";
1617 }
1618 }
1619 else if (visit == PostVisit)
1620 {
1621 out << ";\n";
1622 }
1623 break;
1624 default: UNREACHABLE();
1625 }
1626
1627 return true;
1628}
1629
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001630bool OutputHLSL::isSingleStatement(TIntermNode *node)
1631{
1632 TIntermAggregate *aggregate = node->getAsAggregate();
1633
1634 if (aggregate)
1635 {
1636 if (aggregate->getOp() == EOpSequence)
1637 {
1638 return false;
1639 }
1640 else
1641 {
1642 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1643 {
1644 if (!isSingleStatement(*sit))
1645 {
1646 return false;
1647 }
1648 }
1649
1650 return true;
1651 }
1652 }
1653
1654 return true;
1655}
1656
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001657// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1658bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1659{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001660 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001661
1662 // Parse loops of the form:
1663 // for(int index = initial; index [comparator] limit; index += increment)
1664 TIntermSymbol *index = NULL;
1665 TOperator comparator = EOpNull;
1666 int initial = 0;
1667 int limit = 0;
1668 int increment = 0;
1669
1670 // Parse index name and intial value
1671 if (node->getInit())
1672 {
1673 TIntermAggregate *init = node->getInit()->getAsAggregate();
1674
1675 if (init)
1676 {
1677 TIntermSequence &sequence = init->getSequence();
1678 TIntermTyped *variable = sequence[0]->getAsTyped();
1679
1680 if (variable && variable->getQualifier() == EvqTemporary)
1681 {
1682 TIntermBinary *assign = variable->getAsBinaryNode();
1683
1684 if (assign->getOp() == EOpInitialize)
1685 {
1686 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1687 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1688
1689 if (symbol && constant)
1690 {
1691 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1692 {
1693 index = symbol;
1694 initial = constant->getUnionArrayPointer()[0].getIConst();
1695 }
1696 }
1697 }
1698 }
1699 }
1700 }
1701
1702 // Parse comparator and limit value
1703 if (index != NULL && node->getTest())
1704 {
1705 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1706
1707 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1708 {
1709 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1710
1711 if (constant)
1712 {
1713 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1714 {
1715 comparator = test->getOp();
1716 limit = constant->getUnionArrayPointer()[0].getIConst();
1717 }
1718 }
1719 }
1720 }
1721
1722 // Parse increment
1723 if (index != NULL && comparator != EOpNull && node->getTerminal())
1724 {
1725 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1726 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1727
1728 if (binaryTerminal)
1729 {
1730 TOperator op = binaryTerminal->getOp();
1731 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1732
1733 if (constant)
1734 {
1735 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1736 {
1737 int value = constant->getUnionArrayPointer()[0].getIConst();
1738
1739 switch (op)
1740 {
1741 case EOpAddAssign: increment = value; break;
1742 case EOpSubAssign: increment = -value; break;
1743 default: UNIMPLEMENTED();
1744 }
1745 }
1746 }
1747 }
1748 else if (unaryTerminal)
1749 {
1750 TOperator op = unaryTerminal->getOp();
1751
1752 switch (op)
1753 {
1754 case EOpPostIncrement: increment = 1; break;
1755 case EOpPostDecrement: increment = -1; break;
1756 case EOpPreIncrement: increment = 1; break;
1757 case EOpPreDecrement: increment = -1; break;
1758 default: UNIMPLEMENTED();
1759 }
1760 }
1761 }
1762
1763 if (index != NULL && comparator != EOpNull && increment != 0)
1764 {
1765 if (comparator == EOpLessThanEqual)
1766 {
1767 comparator = EOpLessThan;
1768 limit += 1;
1769 }
1770
1771 if (comparator == EOpLessThan)
1772 {
1773 int iterations = (limit - initial + 1) / increment;
1774
1775 if (iterations <= 255)
1776 {
1777 return false; // Not an excessive loop
1778 }
1779
1780 while (iterations > 0)
1781 {
1782 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001783 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001784
1785 // for(int index = initial; index < clampedLimit; index += increment)
1786
1787 out << "for(int ";
1788 index->traverse(this);
1789 out << " = ";
1790 out << initial;
1791
1792 out << "; ";
1793 index->traverse(this);
1794 out << " < ";
1795 out << clampedLimit;
1796
1797 out << "; ";
1798 index->traverse(this);
1799 out << " += ";
1800 out << increment;
1801 out << ")\n"
1802 "{\n";
1803
1804 if (node->getBody())
1805 {
1806 node->getBody()->traverse(this);
1807 }
1808
1809 out << "}\n";
1810
1811 initial += 255 * increment;
1812 iterations -= 255;
1813 }
1814
1815 return true;
1816 }
1817 else UNIMPLEMENTED();
1818 }
1819
1820 return false; // Not handled as an excessive loop
1821}
1822
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001823void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1824{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001825 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001826
1827 if (visit == PreVisit && preString)
1828 {
1829 out << preString;
1830 }
1831 else if (visit == InVisit && inString)
1832 {
1833 out << inString;
1834 }
1835 else if (visit == PostVisit && postString)
1836 {
1837 out << postString;
1838 }
1839}
1840
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001841TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1842{
1843 TQualifier qualifier = symbol->getQualifier();
1844 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001845 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001846
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001847 if (name.empty()) // HLSL demands named arguments, also for prototypes
1848 {
1849 name = "x" + str(mArgumentIndex++);
1850 }
1851 else
1852 {
1853 name = decorate(name);
1854 }
1855
1856 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001857}
1858
1859TString OutputHLSL::qualifierString(TQualifier qualifier)
1860{
1861 switch(qualifier)
1862 {
1863 case EvqIn: return "in";
1864 case EvqOut: return "out";
1865 case EvqInOut: return "inout";
1866 case EvqConstReadOnly: return "const";
1867 default: UNREACHABLE();
1868 }
1869
1870 return "";
1871}
1872
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001873TString OutputHLSL::typeString(const TType &type)
1874{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001875 if (type.getBasicType() == EbtStruct)
1876 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001877 return decorate(type.getTypeName());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001878 }
1879 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001880 {
1881 switch (type.getNominalSize())
1882 {
1883 case 2: return "float2x2";
1884 case 3: return "float3x3";
1885 case 4: return "float4x4";
1886 }
1887 }
1888 else
1889 {
1890 switch (type.getBasicType())
1891 {
1892 case EbtFloat:
1893 switch (type.getNominalSize())
1894 {
1895 case 1: return "float";
1896 case 2: return "float2";
1897 case 3: return "float3";
1898 case 4: return "float4";
1899 }
1900 case EbtInt:
1901 switch (type.getNominalSize())
1902 {
1903 case 1: return "int";
1904 case 2: return "int2";
1905 case 3: return "int3";
1906 case 4: return "int4";
1907 }
1908 case EbtBool:
1909 switch (type.getNominalSize())
1910 {
1911 case 1: return "bool";
1912 case 2: return "bool2";
1913 case 3: return "bool3";
1914 case 4: return "bool4";
1915 }
1916 case EbtVoid:
1917 return "void";
1918 case EbtSampler2D:
1919 return "sampler2D";
1920 case EbtSamplerCube:
1921 return "samplerCUBE";
1922 }
1923 }
1924
1925 UNIMPLEMENTED(); // FIXME
1926 return "<unknown type>";
1927}
1928
1929TString OutputHLSL::arrayString(const TType &type)
1930{
1931 if (!type.isArray())
1932 {
1933 return "";
1934 }
1935
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001936 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001937}
1938
1939TString OutputHLSL::initializer(const TType &type)
1940{
1941 TString string;
1942
1943 int arraySize = type.isArray() ? type.getArraySize() : 1;
1944
1945 if (type.isArray())
1946 {
1947 string += "{";
1948 }
1949
1950 for (int element = 0; element < arraySize; element++)
1951 {
1952 string += typeString(type) + "(";
1953
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001954 for (int component = 0; component < type.getInstanceSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001955 {
1956 string += "0";
1957
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001958 if (component < type.getInstanceSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001959 {
1960 string += ", ";
1961 }
1962 }
1963
1964 string += ")";
1965
1966 if (element < arraySize - 1)
1967 {
1968 string += ", ";
1969 }
1970 }
1971
1972 if (type.isArray())
1973 {
1974 string += "}";
1975 }
1976
1977 return string;
1978}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001979
1980TString OutputHLSL::decorate(const TString &string)
1981{
1982 if (string.substr(0, 3) != "gl_")
1983 {
1984 return "_" + string;
1985 }
1986 else
1987 {
1988 return string;
1989 }
1990}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001991}