blob: 06d715dccd369ccf86bdb18fa4b93bd67e59045a [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.com0bbb0312010-04-26 15:33:39 +000035 mUsesFaceforward1 = false;
36 mUsesFaceforward2 = false;
37 mUsesFaceforward3 = false;
38 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000039 mUsesEqualMat2 = false;
40 mUsesEqualMat3 = false;
41 mUsesEqualMat4 = false;
42 mUsesEqualVec2 = false;
43 mUsesEqualVec3 = false;
44 mUsesEqualVec4 = false;
45 mUsesEqualIVec2 = false;
46 mUsesEqualIVec3 = false;
47 mUsesEqualIVec4 = false;
48 mUsesEqualBVec2 = false;
49 mUsesEqualBVec3 = false;
50 mUsesEqualBVec4 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000051
52 mArgumentIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053}
54
daniel@transgaming.comb5875982010-04-15 20:44:53 +000055OutputHLSL::~OutputHLSL()
56{
57 delete mUnfoldSelect;
58}
59
daniel@transgaming.com950f9932010-04-13 03:26:14 +000060void OutputHLSL::output()
61{
62 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
63 header();
64 footer();
65
66 mContext.infoSink.obj << mHeader.c_str();
67 mContext.infoSink.obj << mBody.c_str();
68 mContext.infoSink.obj << mFooter.c_str();
69}
70
daniel@transgaming.comb5875982010-04-15 20:44:53 +000071TInfoSinkBase &OutputHLSL::getBodyStream()
72{
73 return mBody;
74}
75
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076void OutputHLSL::header()
77{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000078 EShLanguage language = mContext.language;
79 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080
81 if (language == EShLangFragment)
82 {
83 TString uniforms;
84 TString varyingInput;
85 TString varyingGlobals;
86
daniel@transgaming.com950f9932010-04-13 03:26:14 +000087 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000088 int semanticIndex = 0;
89
90 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
91 {
92 const TSymbol *symbol = (*namedSymbol).second;
93 const TString &name = symbol->getName();
94
95 if (symbol->isVariable())
96 {
97 const TVariable *variable = static_cast<const TVariable*>(symbol);
98 const TType &type = variable->getType();
99 TQualifier qualifier = type.getQualifier();
100
101 if (qualifier == EvqUniform)
102 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000103 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
104 {
105 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
106 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 }
108 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
109 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000110 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
111 {
112 // Program linking depends on this exact format
113 varyingInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
114 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000115
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000116 semanticIndex += type.isArray() ? type.getArraySize() : 1;
117 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000119 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000120 {
121 // Globals are declared and intialized as an aggregate node
122 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000123 else if (qualifier == EvqConst)
124 {
125 // Constants are repeated as literals where used
126 }
127 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128 }
129 }
130
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000131 out << "uniform float4 dx_Window;\n"
132 "uniform float2 dx_Depth;\n"
133 "uniform bool dx_PointsOrLines;\n"
134 "uniform bool dx_FrontCCW;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000135 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136 out << uniforms;
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000137 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000138 "struct PS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139 "{\n";
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000140 out << varyingInput;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000141 out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000142 out << " float vFace : VFACE;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000143 "};\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 "\n";
145 out << varyingGlobals;
146 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000147 "struct PS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148 "{\n"
149 " float4 gl_Color[1] : COLOR;\n"
150 "};\n"
151 "\n"
152 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000153 "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000154 "static float2 gl_PointCoord = float2(0.5, 0.5);\n"
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000155 "static bool gl_FrontFacing = false;\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156 "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000157
158 if (mUsesTexture2D)
159 {
160 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
161 "{\n"
162 " return tex2D(s, t);\n"
163 "}\n"
164 "\n";
165 }
166
167 if (mUsesTexture2D_bias)
168 {
169 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
170 "{\n"
171 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
172 "}\n"
173 "\n";
174 }
175
176 if (mUsesTexture2DProj)
177 {
178 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
179 "{\n"
180 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
181 "}\n"
182 "\n"
183 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
184 "{\n"
185 " return tex2Dproj(s, t);\n"
186 "}\n"
187 "\n";
188 }
189
190 if (mUsesTexture2DProj_bias)
191 {
192 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
193 "{\n"
194 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
195 "}\n"
196 "\n"
197 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
198 "{\n"
199 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
200 "}\n"
201 "\n";
202 }
203
204 if (mUsesTextureCube)
205 {
206 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
207 "{\n"
208 " return texCUBE(s, t);\n"
209 "}\n"
210 "\n";
211 }
212
213 if (mUsesTextureCube_bias)
214 {
215 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
216 "{\n"
217 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
218 "}\n"
219 "\n";
220 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000222 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 {
224 TString uniforms;
225 TString attributeInput;
226 TString attributeGlobals;
227 TString varyingOutput;
228 TString varyingGlobals;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000230 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231 int semanticIndex = 0;
232
233 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
234 {
235 const TSymbol *symbol = (*namedSymbol).second;
236 const TString &name = symbol->getName();
237
238 if (symbol->isVariable())
239 {
240 const TVariable *variable = static_cast<const TVariable*>(symbol);
241 const TType &type = variable->getType();
242 TQualifier qualifier = type.getQualifier();
243
244 if (qualifier == EvqUniform)
245 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000246 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
247 {
248 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
249 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250 }
251 else if (qualifier == EvqAttribute)
252 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000253 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
254 {
255 attributeInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
256 attributeGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000257
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000258 semanticIndex += type.isArray() ? type.getArraySize() : 1;
259 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 }
261 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
262 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000263 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
264 {
265 // Program linking depends on this exact format
266 varyingOutput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
267 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
268 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000270 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000272 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000274 else if (qualifier == EvqConst)
275 {
276 // Constants are repeated as literals where used
277 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 else UNREACHABLE();
279 }
280 }
281
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000282 out << "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000283 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 out << uniforms;
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000285 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000286 "struct VS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 "{\n";
288 out << attributeInput;
289 out << "};\n"
290 "\n";
291 out << attributeGlobals;
292 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000293 "struct VS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294 "{\n"
295 " float4 gl_Position : POSITION;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000296 " float gl_PointSize : PSIZE;\n"
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000297 " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000298 out << varyingOutput;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 out << "};\n"
300 "\n"
301 "static float4 gl_Position = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000302 "static float gl_PointSize = float(1);\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 out << varyingGlobals;
304 out << "\n";
305 }
306
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000307 out << "struct gl_DepthRangeParameters\n"
308 "{\n"
309 " float near;\n"
310 " float far;\n"
311 " float diff;\n"
312 "};\n"
313 "\n"
314 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
315 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000316 "float vec1(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317 "{\n"
318 " return x;\n"
319 "}\n"
320 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000321 "float vec1(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322 "{\n"
323 " return xy[0];\n"
324 "}\n"
325 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000326 "float vec1(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327 "{\n"
328 " return xyz[0];\n"
329 "}\n"
330 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000331 "float vec1(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 "{\n"
333 " return xyzw[0];\n"
334 "}\n"
335 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000336 "float2 vec2(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337 "{\n"
338 " return float2(x, x);\n"
339 "}\n"
340 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000341 "float2 vec2(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342 "{\n"
343 " return float2(x, y);\n"
344 "}\n"
345 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000346 "float2 vec2(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347 "{\n"
348 " return xy;\n"
349 "}\n"
350 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000351 "float2 vec2(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 "{\n"
353 " return float2(xyz[0], xyz[1]);\n"
354 "}\n"
355 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000356 "float2 vec2(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357 "{\n"
358 " return float2(xyzw[0], xyzw[1]);\n"
359 "}\n"
360 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000361 "float3 vec3(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 "{\n"
363 " return float3(x, x, x);\n"
364 "}\n"
365 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000366 "float3 vec3(float x, float y, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367 "{\n"
368 " return float3(x, y, z);\n"
369 "}\n"
370 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000371 "float3 vec3(float2 xy, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372 "{\n"
373 " return float3(xy[0], xy[1], z);\n"
374 "}\n"
375 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000376 "float3 vec3(float x, float2 yz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377 "{\n"
378 " return float3(x, yz[0], yz[1]);\n"
379 "}\n"
380 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000381 "float3 vec3(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382 "{\n"
383 " return xyz;\n"
384 "}\n"
385 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000386 "float3 vec3(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387 "{\n"
388 " return float3(xyzw[0], xyzw[1], xyzw[2]);\n"
389 "}\n"
390 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000391 "float4 vec4(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 "{\n"
393 " return float4(x, x, x, x);\n"
394 "}\n"
395 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000396 "float4 vec4(float x, float y, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000397 "{\n"
398 " return float4(x, y, z, w);\n"
399 "}\n"
400 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000401 "float4 vec4(float2 xy, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402 "{\n"
403 " return float4(xy[0], xy[1], z, w);\n"
404 "}\n"
405 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000406 "float4 vec4(float x, float2 yz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407 "{\n"
408 " return float4(x, yz[0], yz[1], w);\n"
409 "}\n"
410 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000411 "float4 vec4(float x, float y, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000412 "{\n"
413 " return float4(x, y, zw[0], zw[1]);\n"
414 "}\n"
415 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000416 "float4 vec4(float2 xy, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000417 "{\n"
418 " return float4(xy[0], xy[1], zw[0], zw[1]);\n"
419 "}\n"
420 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000421 "float4 vec4(float3 xyz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422 "{\n"
423 " return float4(xyz[0], xyz[1], xyz[2], w);\n"
424 "}\n"
425 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000426 "float4 vec4(float x, float3 yzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427 "{\n"
428 " return float4(x, yzw[0], yzw[1], yzw[2]);\n"
429 "}\n"
430 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000431 "float4 vec4(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 "{\n"
433 " return xyzw;\n"
434 "}\n"
435 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000436 "bool xor(bool p, bool q)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437 "{\n"
438 " return (p || q) && !(p && q);\n"
439 "}\n"
440 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000441 "float mod(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 "{\n"
443 " return x - y * floor(x / y);\n"
444 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000445 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000446 "float2 mod(float2 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 "{\n"
448 " return x - y * floor(x / y);\n"
449 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000450 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000451 "float3 mod(float3 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452 "{\n"
453 " return x - y * floor(x / y);\n"
454 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000455 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000456 "float4 mod(float4 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457 "{\n"
458 " return x - y * floor(x / y);\n"
459 "}\n"
460 "\n";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000461
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000462 if (mUsesFaceforward1)
463 {
464 out << "float faceforward(float N, float I, float Nref)\n"
465 "{\n"
466 " if(dot(Nref, I) < 0)\n"
467 " {\n"
468 " return N;\n"
469 " }\n"
470 " else\n"
471 " {\n"
472 " return -N;\n"
473 " }\n"
474 "}\n"
475 "\n";
476 }
477
478 if (mUsesFaceforward2)
479 {
480 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
481 "{\n"
482 " if(dot(Nref, I) < 0)\n"
483 " {\n"
484 " return N;\n"
485 " }\n"
486 " else\n"
487 " {\n"
488 " return -N;\n"
489 " }\n"
490 "}\n"
491 "\n";
492 }
493
494 if (mUsesFaceforward3)
495 {
496 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
497 "{\n"
498 " if(dot(Nref, I) < 0)\n"
499 " {\n"
500 " return N;\n"
501 " }\n"
502 " else\n"
503 " {\n"
504 " return -N;\n"
505 " }\n"
506 "}\n"
507 "\n";
508 }
509
510 if (mUsesFaceforward4)
511 {
512 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
513 "{\n"
514 " if(dot(Nref, I) < 0)\n"
515 " {\n"
516 " return N;\n"
517 " }\n"
518 " else\n"
519 " {\n"
520 " return -N;\n"
521 " }\n"
522 "}\n"
523 "\n";
524 }
525
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000526 if (mUsesEqualMat2)
527 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000528 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000529 "{\n"
530 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
531 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
532 "}\n";
533 }
534
535 if (mUsesEqualMat3)
536 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000537 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000538 "{\n"
539 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
540 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
541 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
542 "}\n";
543 }
544
545 if (mUsesEqualMat4)
546 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000547 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000548 "{\n"
549 " 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"
550 " 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"
551 " 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"
552 " 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"
553 "}\n";
554 }
555
556 if (mUsesEqualVec2)
557 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000558 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000559 "{\n"
560 " return v.x == u.x && v.y == u.y;\n"
561 "}\n";
562 }
563
564 if (mUsesEqualVec3)
565 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000566 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000567 "{\n"
568 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
569 "}\n";
570 }
571
572 if (mUsesEqualVec4)
573 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000574 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000575 "{\n"
576 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
577 "}\n";
578 }
579
580 if (mUsesEqualIVec2)
581 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000582 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000583 "{\n"
584 " return v.x == u.x && v.y == u.y;\n"
585 "}\n";
586 }
587
588 if (mUsesEqualIVec3)
589 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000590 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000591 "{\n"
592 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
593 "}\n";
594 }
595
596 if (mUsesEqualIVec4)
597 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000598 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000599 "{\n"
600 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
601 "}\n";
602 }
603
604 if (mUsesEqualBVec2)
605 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000606 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000607 "{\n"
608 " return v.x == u.x && v.y == u.y;\n"
609 "}\n";
610 }
611
612 if (mUsesEqualBVec3)
613 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000614 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000615 "{\n"
616 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
617 "}\n";
618 }
619
620 if (mUsesEqualBVec4)
621 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000622 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000623 "{\n"
624 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
625 "}\n";
626 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000627}
628
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000629void OutputHLSL::footer()
630{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000631 EShLanguage language = mContext.language;
632 TInfoSinkBase &out = mFooter;
633 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000634
635 if (language == EShLangFragment)
636 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000637 out << "PS_OUTPUT main(PS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000638 "{\n"
639 " float rhw = 1.0 / input.gl_FragCoord.w;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000640 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Window.x + dx_Window.z;\n"
641 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Window.y + dx_Window.w;\n"
642 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000643 " gl_FragCoord.w = rhw;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000644 " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000645
646 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
647 {
648 const TSymbol *symbol = (*namedSymbol).second;
649 const TString &name = symbol->getName();
650
651 if (symbol->isVariable())
652 {
653 const TVariable *variable = static_cast<const TVariable*>(symbol);
654 const TType &type = variable->getType();
655 TQualifier qualifier = type.getQualifier();
656
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000657 if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000658 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000659 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
660 {
661 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
662 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000663 }
664 }
665 }
666
667 out << "\n"
668 " gl_main();\n"
669 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000670 " PS_OUTPUT output;\n"
671 " output.gl_Color[0] = gl_Color[0];\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000672 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000673 else // Vertex shader
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000674 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000675 out << "VS_OUTPUT main(VS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000676 "{\n";
677
678 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
679 {
680 const TSymbol *symbol = (*namedSymbol).second;
681 const TString &name = symbol->getName();
682
683 if (symbol->isVariable())
684 {
685 const TVariable *variable = static_cast<const TVariable*>(symbol);
686 const TType &type = variable->getType();
687 TQualifier qualifier = type.getQualifier();
688
689 if (qualifier == EvqAttribute)
690 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000691 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
692 {
693 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
694 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000695 }
696 }
697 }
698
699 out << "\n"
700 " gl_main();\n"
701 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000702 " VS_OUTPUT output;\n"
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000703 " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
704 " output.gl_Position.y = -(gl_Position.y - dx_HalfPixelSize.y * gl_Position.w);\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000705 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
706 " output.gl_Position.w = gl_Position.w;\n"
707 " output.gl_PointSize = gl_PointSize;\n"
708 " output.gl_FragCoord = gl_Position;\n";
709
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000710 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000711
712 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
713 {
714 const TSymbol *symbol = (*namedSymbol).second;
715 const TString &name = symbol->getName();
716
717 if (symbol->isVariable())
718 {
719 const TVariable *variable = static_cast<const TVariable*>(symbol);
720 TQualifier qualifier = variable->getType().getQualifier();
721
722 if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
723 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000724 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
725 {
726 // Program linking depends on this exact format
727 out << " output." + decorate(name) + " = " + decorate(name) + ";\n";
728 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000729 }
730 }
731 }
732 }
733
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000734 out << " return output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000735 "}\n";
736}
737
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738void OutputHLSL::visitSymbol(TIntermSymbol *node)
739{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000740 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741
742 TString name = node->getSymbol();
743
744 if (name == "gl_FragColor")
745 {
746 out << "gl_Color[0]";
747 }
748 else if (name == "gl_FragData")
749 {
750 out << "gl_Color";
751 }
752 else
753 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000754 TQualifier qualifier = node->getQualifier();
755
756 if (qualifier == EvqUniform)
757 {
758 mReferencedUniforms.insert(name.c_str());
759 }
760 else if (qualifier == EvqAttribute)
761 {
762 mReferencedAttributes.insert(name.c_str());
763 }
764 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
765 {
766 mReferencedVaryings.insert(name.c_str());
767 }
768
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000769 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000770 }
771}
772
773bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
774{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000775 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000776
777 switch (node->getOp())
778 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000779 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
780 case EOpInitialize: outputTriplet(visit, NULL, " = ", NULL); break;
781 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
782 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
783 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
784 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
785 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
786 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000787 if (visit == PreVisit)
788 {
789 out << "(";
790 }
791 else if (visit == InVisit)
792 {
793 out << " = mul(";
794 node->getLeft()->traverse(this);
795 out << ", transpose(";
796 }
797 else
798 {
799 out << "))";
800 }
801 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000802 case EOpMatrixTimesMatrixAssign:
803 if (visit == PreVisit)
804 {
805 out << "(";
806 }
807 else if (visit == InVisit)
808 {
809 out << " = mul(";
810 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000811 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000812 }
813 else
814 {
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000815 out << ")";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000816 }
817 break;
818 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
819 case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break;
820 case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break;
821 case EOpIndexDirectStruct: outputTriplet(visit, NULL, ".", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000822 case EOpVectorSwizzle:
823 if (visit == InVisit)
824 {
825 out << ".";
826
827 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
828
829 if (swizzle)
830 {
831 TIntermSequence &sequence = swizzle->getSequence();
832
833 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
834 {
835 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
836
837 if (element)
838 {
839 int i = element->getUnionArrayPointer()[0].getIConst();
840
841 switch (i)
842 {
843 case 0: out << "x"; break;
844 case 1: out << "y"; break;
845 case 2: out << "z"; break;
846 case 3: out << "w"; break;
847 default: UNREACHABLE();
848 }
849 }
850 else UNREACHABLE();
851 }
852 }
853 else UNREACHABLE();
854
855 return false; // Fully processed
856 }
857 break;
858 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
859 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
860 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
861 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000862 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000863 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000864 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000865 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000866 if (node->getOp() == EOpEqual)
867 {
868 outputTriplet(visit, "(", " == ", ")");
869 }
870 else
871 {
872 outputTriplet(visit, "(", " != ", ")");
873 }
874 }
875 else if (node->getLeft()->getBasicType() == EbtStruct)
876 {
877 if (node->getOp() == EOpEqual)
878 {
879 out << "(";
880 }
881 else
882 {
883 out << "!(";
884 }
885
886 const TTypeList *fields = node->getLeft()->getType().getStruct();
887
888 for (size_t i = 0; i < fields->size(); i++)
889 {
890 const TType *fieldType = (*fields)[i].type;
891
892 node->getLeft()->traverse(this);
893 out << "." + fieldType->getFieldName() + " == ";
894 node->getRight()->traverse(this);
895 out << "." + fieldType->getFieldName();
896
897 if (i < fields->size() - 1)
898 {
899 out << " && ";
900 }
901 }
902
903 out << ")";
904
905 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000906 }
907 else
908 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000909 if (node->getLeft()->isMatrix())
910 {
911 switch (node->getLeft()->getSize())
912 {
913 case 2 * 2: mUsesEqualMat2 = true; break;
914 case 3 * 3: mUsesEqualMat3 = true; break;
915 case 4 * 4: mUsesEqualMat4 = true; break;
916 default: UNREACHABLE();
917 }
918 }
919 else if (node->getLeft()->isVector())
920 {
921 switch (node->getLeft()->getBasicType())
922 {
923 case EbtFloat:
924 switch (node->getLeft()->getSize())
925 {
926 case 2: mUsesEqualVec2 = true; break;
927 case 3: mUsesEqualVec3 = true; break;
928 case 4: mUsesEqualVec4 = true; break;
929 default: UNREACHABLE();
930 }
931 break;
932 case EbtInt:
933 switch (node->getLeft()->getSize())
934 {
935 case 2: mUsesEqualIVec2 = true; break;
936 case 3: mUsesEqualIVec3 = true; break;
937 case 4: mUsesEqualIVec4 = true; break;
938 default: UNREACHABLE();
939 }
940 break;
941 case EbtBool:
942 switch (node->getLeft()->getSize())
943 {
944 case 2: mUsesEqualBVec2 = true; break;
945 case 3: mUsesEqualBVec3 = true; break;
946 case 4: mUsesEqualBVec4 = true; break;
947 default: UNREACHABLE();
948 }
949 break;
950 default: UNREACHABLE();
951 }
952 }
953 else UNREACHABLE();
954
955 if (node->getOp() == EOpEqual)
956 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000957 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000958 }
959 else
960 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000961 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000962 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000963 }
964 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
966 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
967 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
968 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
969 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000970 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000971 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
972 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +0000973 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000974 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000975 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000976 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
977 default: UNREACHABLE();
978 }
979
980 return true;
981}
982
983bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
984{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000985 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000986
987 switch (node->getOp())
988 {
989 case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break;
990 case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
991 case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000992 case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break;
993 case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break;
994 case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break;
995 case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break;
996 case EOpConvIntToBool:
997 case EOpConvFloatToBool:
998 switch (node->getOperand()->getType().getNominalSize())
999 {
1000 case 1: outputTriplet(visit, "bool(", NULL, ")"); break;
1001 case 2: outputTriplet(visit, "bool2(", NULL, ")"); break;
1002 case 3: outputTriplet(visit, "bool3(", NULL, ")"); break;
1003 case 4: outputTriplet(visit, "bool4(", NULL, ")"); break;
1004 default: UNREACHABLE();
1005 }
1006 break;
1007 case EOpConvBoolToFloat:
1008 case EOpConvIntToFloat:
1009 switch (node->getOperand()->getType().getNominalSize())
1010 {
1011 case 1: outputTriplet(visit, "float(", NULL, ")"); break;
1012 case 2: outputTriplet(visit, "float2(", NULL, ")"); break;
1013 case 3: outputTriplet(visit, "float3(", NULL, ")"); break;
1014 case 4: outputTriplet(visit, "float4(", NULL, ")"); break;
1015 default: UNREACHABLE();
1016 }
1017 break;
1018 case EOpConvFloatToInt:
1019 case EOpConvBoolToInt:
1020 switch (node->getOperand()->getType().getNominalSize())
1021 {
1022 case 1: outputTriplet(visit, "int(", NULL, ")"); break;
1023 case 2: outputTriplet(visit, "int2(", NULL, ")"); break;
1024 case 3: outputTriplet(visit, "int3(", NULL, ")"); break;
1025 case 4: outputTriplet(visit, "int4(", NULL, ")"); break;
1026 default: UNREACHABLE();
1027 }
1028 break;
1029 case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break;
1030 case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break;
1031 case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break;
1032 case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break;
1033 case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break;
1034 case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break;
1035 case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break;
1036 case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break;
1037 case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break;
1038 case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break;
1039 case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break;
1040 case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break;
1041 case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break;
1042 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break;
1043 case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break;
1044 case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break;
1045 case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break;
1046 case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break;
1047 case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break;
1048 case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break;
1049 case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break;
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001050// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break;
1051// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break;
1052// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001053 case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break;
1054 case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break;
1055 default: UNREACHABLE();
1056 }
1057
1058 return true;
1059}
1060
1061bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1062{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001063 EShLanguage language = mContext.language;
1064 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001066 switch (node->getOp())
1067 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001068 case EOpSequence:
1069 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001070 if (mInsideFunction)
1071 {
1072 out << "{\n";
1073 }
1074
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001075 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1076 {
1077 if (isSingleStatement(*sit))
1078 {
1079 mUnfoldSelect->traverse(*sit);
1080 }
1081
1082 (*sit)->traverse(this);
1083
1084 out << ";\n";
1085 }
1086
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001087 if (mInsideFunction)
1088 {
1089 out << "}\n";
1090 }
1091
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001092 return false;
1093 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001094 case EOpDeclaration:
1095 if (visit == PreVisit)
1096 {
1097 TIntermSequence &sequence = node->getSequence();
1098 TIntermTyped *variable = sequence[0]->getAsTyped();
1099 bool visit = true;
1100
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001101 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001102 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001103 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001104 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001105 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001106 {
1107 out << "static ";
1108 }
1109
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001110 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001112 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001113 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001114 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001116 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001117 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001118 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001119 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001120 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001121 }
1122 else
1123 {
1124 (*sit)->traverse(this);
1125 }
1126
1127 if (visit && this->inVisit)
1128 {
1129 if (*sit != sequence.back())
1130 {
1131 visit = this->visitAggregate(InVisit, node);
1132 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133 }
1134 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001136 if (visit && this->postVisit)
1137 {
1138 this->visitAggregate(PostVisit, node);
1139 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001141 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1142 {
1143 const TType &type = variable->getType();
1144 const TTypeList &fields = *type.getStruct();
1145
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001146 out << "struct " + decorate(type.getTypeName()) + "\n"
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001147 "{\n";
1148
1149 for (unsigned int i = 0; i < fields.size(); i++)
1150 {
1151 const TType &field = *fields[i].type;
1152
1153 out << " " + typeString(field) + " " + field.getFieldName() + ";\n";
1154 }
1155
1156 out << "};\n";
1157 }
1158 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001159 }
1160
1161 return false;
1162 }
1163 else if (visit == InVisit)
1164 {
1165 out << ", ";
1166 }
1167 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001168 case EOpPrototype:
1169 if (visit == PreVisit)
1170 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001171 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001172
1173 TIntermSequence &arguments = node->getSequence();
1174
1175 for (unsigned int i = 0; i < arguments.size(); i++)
1176 {
1177 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1178
1179 if (symbol)
1180 {
1181 out << argumentString(symbol);
1182
1183 if (i < arguments.size() - 1)
1184 {
1185 out << ", ";
1186 }
1187 }
1188 else UNREACHABLE();
1189 }
1190
1191 out << ");\n";
1192
1193 return false;
1194 }
1195 break;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001196 case EOpComma: outputTriplet(visit, NULL, ", ", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001197 case EOpFunction:
1198 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001199 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001200
1201 if (visit == PreVisit)
1202 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001203 out << typeString(node->getType()) << " ";
1204
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205 if (name == "main")
1206 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001207 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001208 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001209 else
1210 {
1211 out << decorate(name) << "(";
1212 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001213
1214 TIntermSequence &sequence = node->getSequence();
1215 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1216
1217 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001219 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001220
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001221 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001222 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001223 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001224
1225 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001226 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001227 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001229 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001230 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001231 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001232
1233 sequence.erase(sequence.begin());
1234
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001235 out << ")\n";
1236
1237 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238 }
1239 else if (visit == PostVisit)
1240 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001241 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242 }
1243 }
1244 break;
1245 case EOpFunctionCall:
1246 {
1247 if (visit == PreVisit)
1248 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001249 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250
1251 if (node->isUserDefined())
1252 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001253 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001254 }
1255 else
1256 {
1257 if (name == "texture2D")
1258 {
1259 if (node->getSequence().size() == 2)
1260 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001261 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001262 }
1263 else if (node->getSequence().size() == 3)
1264 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001265 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001266 }
1267 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001268
1269 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001270 }
1271 else if (name == "texture2DProj")
1272 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001273 if (node->getSequence().size() == 2)
1274 {
1275 mUsesTexture2DProj = true;
1276 }
1277 else if (node->getSequence().size() == 3)
1278 {
1279 mUsesTexture2DProj_bias = true;
1280 }
1281 else UNREACHABLE();
1282
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283 out << "gl_texture2DProj(";
1284 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001285 else if (name == "textureCube")
1286 {
1287 if (node->getSequence().size() == 2)
1288 {
1289 mUsesTextureCube = true;
1290 }
1291 else if (node->getSequence().size() == 3)
1292 {
1293 mUsesTextureCube_bias = true;
1294 }
1295 else UNREACHABLE();
1296
1297 out << "gl_textureCube(";
1298 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001299 else if (name == "texture2DLod")
1300 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001301 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001302 }
1303 else if (name == "texture2DProjLod")
1304 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001305 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001306 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001307 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001308 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001309 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001310 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001311 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001312 }
1313 }
1314 else if (visit == InVisit)
1315 {
1316 out << ", ";
1317 }
1318 else
1319 {
1320 out << ")";
1321 }
1322 }
1323 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001324 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1325 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1326 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1327 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1328 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001329 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1330 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1331 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1332 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1333 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1334 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1335 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1336 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001337 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1338 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1339 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1340 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1341 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1342 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1343 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1344 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1345 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1346 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001347 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001348 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349 case EOpAtan:
1350 if (node->getSequence().size() == 1)
1351 {
1352 outputTriplet(visit, "atan(", ", ", ")");
1353 }
1354 else if (node->getSequence().size() == 2)
1355 {
1356 outputTriplet(visit, "atan2(", ", ", ")");
1357 }
1358 else UNREACHABLE();
1359 break;
1360 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1361 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1362 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1363 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1364 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1365 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1366 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1367 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1368 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001369 case EOpFaceForward:
1370 {
1371 switch (node->getSequence()[0]->getAsTyped()->getSize()) // Number of components in the first argument
1372 {
1373 case 1: mUsesFaceforward1 = true; break;
1374 case 2: mUsesFaceforward2 = true; break;
1375 case 3: mUsesFaceforward3 = true; break;
1376 case 4: mUsesFaceforward4 = true; break;
1377 default: UNREACHABLE();
1378 }
1379
1380 outputTriplet(visit, "faceforward(", ", ", ")");
1381 }
1382 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001383 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1384 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1385 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001386 default: UNREACHABLE();
1387 }
1388
1389 return true;
1390}
1391
1392bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1393{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001394 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001395
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001396 if (node->usesTernaryOperator())
1397 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001398 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001399 }
1400 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001401 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001402 mUnfoldSelect->traverse(node->getCondition());
1403
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001404 out << "if(";
1405
1406 node->getCondition()->traverse(this);
1407
1408 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001409 "{\n";
1410
daniel@transgaming.combb885322010-04-15 20:45:24 +00001411 if (node->getTrueBlock())
1412 {
1413 node->getTrueBlock()->traverse(this);
1414 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001415
1416 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001417
1418 if (node->getFalseBlock())
1419 {
1420 out << "else\n"
1421 "{\n";
1422
1423 node->getFalseBlock()->traverse(this);
1424
1425 out << ";}\n";
1426 }
1427 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001428
1429 return false;
1430}
1431
1432void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1433{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001434 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001435
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001436 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001437
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001438 if (type.isField())
1439 {
1440 out << type.getFieldName();
1441 }
1442 else
1443 {
1444 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001445
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001446 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001447 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001448 out << "{";
1449 }
1450 else
1451 {
1452 bool matrix = type.isMatrix();
1453 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1454
1455 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001456 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001457 case EbtBool:
1458 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001459 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001460 switch (size)
1461 {
1462 case 1: out << "bool("; break;
1463 case 2: out << "bool2("; break;
1464 case 3: out << "bool3("; break;
1465 case 4: out << "bool4("; break;
1466 default: UNREACHABLE();
1467 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001468 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001469 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001470 break;
1471 case EbtFloat:
1472 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001473 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001474 switch (size)
1475 {
1476 case 1: out << "float("; break;
1477 case 2: out << "float2("; break;
1478 case 3: out << "float3("; break;
1479 case 4: out << "float4("; break;
1480 default: UNREACHABLE();
1481 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001482 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001483 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001484 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001485 switch (size)
1486 {
1487 case 4: out << "float2x2("; break;
1488 case 9: out << "float3x3("; break;
1489 case 16: out << "float4x4("; break;
1490 default: UNREACHABLE();
1491 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001492 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001493 break;
1494 case EbtInt:
1495 if (!matrix)
1496 {
1497 switch (size)
1498 {
1499 case 1: out << "int("; break;
1500 case 2: out << "int2("; break;
1501 case 3: out << "int3("; break;
1502 case 4: out << "int4("; break;
1503 default: UNREACHABLE();
1504 }
1505 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001506 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001507 break;
1508 default:
1509 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001510 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001511 }
1512
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001513 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001514 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001515 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001516 {
1517 case EbtBool:
1518 if (node->getUnionArrayPointer()[i].getBConst())
1519 {
1520 out << "true";
1521 }
1522 else
1523 {
1524 out << "false";
1525 }
1526 break;
1527 case EbtFloat:
1528 out << node->getUnionArrayPointer()[i].getFConst();
1529 break;
1530 case EbtInt:
1531 out << node->getUnionArrayPointer()[i].getIConst();
1532 break;
1533 default:
1534 UNIMPLEMENTED(); // FIXME
1535 }
1536
1537 if (i != size - 1)
1538 {
1539 out << ", ";
1540 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001541 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001542
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001543 if (type.getBasicType() == EbtStruct)
1544 {
1545 out << "}";
1546 }
1547 else
1548 {
1549 out << ")";
1550 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001551 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552}
1553
1554bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1555{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001556 if (handleExcessiveLoop(node))
1557 {
1558 return false;
1559 }
1560
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001561 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001562
1563 if (!node->testFirst())
1564 {
1565 out << "do\n"
1566 "{\n";
1567 }
1568 else
1569 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001570 if (node->getInit())
1571 {
1572 mUnfoldSelect->traverse(node->getInit());
1573 }
1574
1575 if (node->getTest())
1576 {
1577 mUnfoldSelect->traverse(node->getTest());
1578 }
1579
1580 if (node->getTerminal())
1581 {
1582 mUnfoldSelect->traverse(node->getTerminal());
1583 }
1584
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001585 out << "for(";
1586
1587 if (node->getInit())
1588 {
1589 node->getInit()->traverse(this);
1590 }
1591
1592 out << "; ";
1593
1594 if (node->getTest())
1595 {
1596 node->getTest()->traverse(this);
1597 }
1598
1599 out << "; ";
1600
1601 if (node->getTerminal())
1602 {
1603 node->getTerminal()->traverse(this);
1604 }
1605
1606 out << ")\n"
1607 "{\n";
1608 }
1609
1610 if (node->getBody())
1611 {
1612 node->getBody()->traverse(this);
1613 }
1614
1615 out << "}\n";
1616
1617 if (!node->testFirst())
1618 {
1619 out << "while(\n";
1620
1621 node->getTest()->traverse(this);
1622
1623 out << ")";
1624 }
1625
1626 out << ";\n";
1627
1628 return false;
1629}
1630
1631bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1632{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001633 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001634
1635 switch (node->getFlowOp())
1636 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001637 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1638 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1639 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 case EOpReturn:
1641 if (visit == PreVisit)
1642 {
1643 if (node->getExpression())
1644 {
1645 out << "return ";
1646 }
1647 else
1648 {
1649 out << "return;\n";
1650 }
1651 }
1652 else if (visit == PostVisit)
1653 {
1654 out << ";\n";
1655 }
1656 break;
1657 default: UNREACHABLE();
1658 }
1659
1660 return true;
1661}
1662
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001663bool OutputHLSL::isSingleStatement(TIntermNode *node)
1664{
1665 TIntermAggregate *aggregate = node->getAsAggregate();
1666
1667 if (aggregate)
1668 {
1669 if (aggregate->getOp() == EOpSequence)
1670 {
1671 return false;
1672 }
1673 else
1674 {
1675 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1676 {
1677 if (!isSingleStatement(*sit))
1678 {
1679 return false;
1680 }
1681 }
1682
1683 return true;
1684 }
1685 }
1686
1687 return true;
1688}
1689
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001690// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1691bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1692{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001693 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001694
1695 // Parse loops of the form:
1696 // for(int index = initial; index [comparator] limit; index += increment)
1697 TIntermSymbol *index = NULL;
1698 TOperator comparator = EOpNull;
1699 int initial = 0;
1700 int limit = 0;
1701 int increment = 0;
1702
1703 // Parse index name and intial value
1704 if (node->getInit())
1705 {
1706 TIntermAggregate *init = node->getInit()->getAsAggregate();
1707
1708 if (init)
1709 {
1710 TIntermSequence &sequence = init->getSequence();
1711 TIntermTyped *variable = sequence[0]->getAsTyped();
1712
1713 if (variable && variable->getQualifier() == EvqTemporary)
1714 {
1715 TIntermBinary *assign = variable->getAsBinaryNode();
1716
1717 if (assign->getOp() == EOpInitialize)
1718 {
1719 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1720 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1721
1722 if (symbol && constant)
1723 {
1724 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1725 {
1726 index = symbol;
1727 initial = constant->getUnionArrayPointer()[0].getIConst();
1728 }
1729 }
1730 }
1731 }
1732 }
1733 }
1734
1735 // Parse comparator and limit value
1736 if (index != NULL && node->getTest())
1737 {
1738 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1739
1740 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1741 {
1742 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1743
1744 if (constant)
1745 {
1746 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1747 {
1748 comparator = test->getOp();
1749 limit = constant->getUnionArrayPointer()[0].getIConst();
1750 }
1751 }
1752 }
1753 }
1754
1755 // Parse increment
1756 if (index != NULL && comparator != EOpNull && node->getTerminal())
1757 {
1758 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1759 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1760
1761 if (binaryTerminal)
1762 {
1763 TOperator op = binaryTerminal->getOp();
1764 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1765
1766 if (constant)
1767 {
1768 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1769 {
1770 int value = constant->getUnionArrayPointer()[0].getIConst();
1771
1772 switch (op)
1773 {
1774 case EOpAddAssign: increment = value; break;
1775 case EOpSubAssign: increment = -value; break;
1776 default: UNIMPLEMENTED();
1777 }
1778 }
1779 }
1780 }
1781 else if (unaryTerminal)
1782 {
1783 TOperator op = unaryTerminal->getOp();
1784
1785 switch (op)
1786 {
1787 case EOpPostIncrement: increment = 1; break;
1788 case EOpPostDecrement: increment = -1; break;
1789 case EOpPreIncrement: increment = 1; break;
1790 case EOpPreDecrement: increment = -1; break;
1791 default: UNIMPLEMENTED();
1792 }
1793 }
1794 }
1795
1796 if (index != NULL && comparator != EOpNull && increment != 0)
1797 {
1798 if (comparator == EOpLessThanEqual)
1799 {
1800 comparator = EOpLessThan;
1801 limit += 1;
1802 }
1803
1804 if (comparator == EOpLessThan)
1805 {
1806 int iterations = (limit - initial + 1) / increment;
1807
1808 if (iterations <= 255)
1809 {
1810 return false; // Not an excessive loop
1811 }
1812
1813 while (iterations > 0)
1814 {
1815 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001816 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001817
1818 // for(int index = initial; index < clampedLimit; index += increment)
1819
1820 out << "for(int ";
1821 index->traverse(this);
1822 out << " = ";
1823 out << initial;
1824
1825 out << "; ";
1826 index->traverse(this);
1827 out << " < ";
1828 out << clampedLimit;
1829
1830 out << "; ";
1831 index->traverse(this);
1832 out << " += ";
1833 out << increment;
1834 out << ")\n"
1835 "{\n";
1836
1837 if (node->getBody())
1838 {
1839 node->getBody()->traverse(this);
1840 }
1841
1842 out << "}\n";
1843
1844 initial += 255 * increment;
1845 iterations -= 255;
1846 }
1847
1848 return true;
1849 }
1850 else UNIMPLEMENTED();
1851 }
1852
1853 return false; // Not handled as an excessive loop
1854}
1855
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001856void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1857{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001858 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859
1860 if (visit == PreVisit && preString)
1861 {
1862 out << preString;
1863 }
1864 else if (visit == InVisit && inString)
1865 {
1866 out << inString;
1867 }
1868 else if (visit == PostVisit && postString)
1869 {
1870 out << postString;
1871 }
1872}
1873
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001874TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1875{
1876 TQualifier qualifier = symbol->getQualifier();
1877 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001878 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001879
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001880 if (name.empty()) // HLSL demands named arguments, also for prototypes
1881 {
1882 name = "x" + str(mArgumentIndex++);
1883 }
1884 else
1885 {
1886 name = decorate(name);
1887 }
1888
1889 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001890}
1891
1892TString OutputHLSL::qualifierString(TQualifier qualifier)
1893{
1894 switch(qualifier)
1895 {
1896 case EvqIn: return "in";
1897 case EvqOut: return "out";
1898 case EvqInOut: return "inout";
1899 case EvqConstReadOnly: return "const";
1900 default: UNREACHABLE();
1901 }
1902
1903 return "";
1904}
1905
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001906TString OutputHLSL::typeString(const TType &type)
1907{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001908 if (type.getBasicType() == EbtStruct)
1909 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001910 return decorate(type.getTypeName());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001911 }
1912 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001913 {
1914 switch (type.getNominalSize())
1915 {
1916 case 2: return "float2x2";
1917 case 3: return "float3x3";
1918 case 4: return "float4x4";
1919 }
1920 }
1921 else
1922 {
1923 switch (type.getBasicType())
1924 {
1925 case EbtFloat:
1926 switch (type.getNominalSize())
1927 {
1928 case 1: return "float";
1929 case 2: return "float2";
1930 case 3: return "float3";
1931 case 4: return "float4";
1932 }
1933 case EbtInt:
1934 switch (type.getNominalSize())
1935 {
1936 case 1: return "int";
1937 case 2: return "int2";
1938 case 3: return "int3";
1939 case 4: return "int4";
1940 }
1941 case EbtBool:
1942 switch (type.getNominalSize())
1943 {
1944 case 1: return "bool";
1945 case 2: return "bool2";
1946 case 3: return "bool3";
1947 case 4: return "bool4";
1948 }
1949 case EbtVoid:
1950 return "void";
1951 case EbtSampler2D:
1952 return "sampler2D";
1953 case EbtSamplerCube:
1954 return "samplerCUBE";
1955 }
1956 }
1957
1958 UNIMPLEMENTED(); // FIXME
1959 return "<unknown type>";
1960}
1961
1962TString OutputHLSL::arrayString(const TType &type)
1963{
1964 if (!type.isArray())
1965 {
1966 return "";
1967 }
1968
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001969 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001970}
1971
1972TString OutputHLSL::initializer(const TType &type)
1973{
1974 TString string;
1975
1976 int arraySize = type.isArray() ? type.getArraySize() : 1;
1977
1978 if (type.isArray())
1979 {
1980 string += "{";
1981 }
1982
1983 for (int element = 0; element < arraySize; element++)
1984 {
1985 string += typeString(type) + "(";
1986
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001987 for (int component = 0; component < type.getInstanceSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001988 {
1989 string += "0";
1990
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001991 if (component < type.getInstanceSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001992 {
1993 string += ", ";
1994 }
1995 }
1996
1997 string += ")";
1998
1999 if (element < arraySize - 1)
2000 {
2001 string += ", ";
2002 }
2003 }
2004
2005 if (type.isArray())
2006 {
2007 string += "}";
2008 }
2009
2010 return string;
2011}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002012
2013TString OutputHLSL::decorate(const TString &string)
2014{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002015 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002016 {
2017 return "_" + string;
2018 }
2019 else
2020 {
2021 return string;
2022 }
2023}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002024}