blob: c97c02f9d23c1f6c7639bee360c91c9db8f5c395 [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
7#include "OutputHLSL.h"
8
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +00009#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000010#include "InfoSink.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
12namespace sh
13{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000014OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015{
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000016 mUsesEqualMat2 = false;
17 mUsesEqualMat3 = false;
18 mUsesEqualMat4 = false;
19 mUsesEqualVec2 = false;
20 mUsesEqualVec3 = false;
21 mUsesEqualVec4 = false;
22 mUsesEqualIVec2 = false;
23 mUsesEqualIVec3 = false;
24 mUsesEqualIVec4 = false;
25 mUsesEqualBVec2 = false;
26 mUsesEqualBVec3 = false;
27 mUsesEqualBVec4 = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028}
29
daniel@transgaming.com950f9932010-04-13 03:26:14 +000030void OutputHLSL::output()
31{
32 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
33 header();
34 footer();
35
36 mContext.infoSink.obj << mHeader.c_str();
37 mContext.infoSink.obj << mBody.c_str();
38 mContext.infoSink.obj << mFooter.c_str();
39}
40
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000041void OutputHLSL::header()
42{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000043 EShLanguage language = mContext.language;
44 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000045
46 if (language == EShLangFragment)
47 {
48 TString uniforms;
49 TString varyingInput;
50 TString varyingGlobals;
51
daniel@transgaming.com950f9932010-04-13 03:26:14 +000052 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053 int semanticIndex = 0;
54
55 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
56 {
57 const TSymbol *symbol = (*namedSymbol).second;
58 const TString &name = symbol->getName();
59
60 if (symbol->isVariable())
61 {
62 const TVariable *variable = static_cast<const TVariable*>(symbol);
63 const TType &type = variable->getType();
64 TQualifier qualifier = type.getQualifier();
65
66 if (qualifier == EvqUniform)
67 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +000068 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069 }
70 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
71 {
72 char semantic[100];
73 sprintf(semantic, " : TEXCOORD%d", semanticIndex);
74 semanticIndex += type.isArray() ? type.getArraySize() : 1;
75
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000076 // Program linking depends on this exact format
daniel@transgaming.com72d0b522010-04-13 19:53:44 +000077 varyingInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + semantic + ";\n";
78 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +000080 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +000081 {
82 // Globals are declared and intialized as an aggregate node
83 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +000084 else if (qualifier == EvqConst)
85 {
86 // Constants are repeated as literals where used
87 }
88 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089 }
90 }
91
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +000092 out << "uniform float4 gl_Window;\n"
93 "uniform float2 gl_Depth;\n"
daniel@transgaming.com72d0b522010-04-13 19:53:44 +000094 "uniform bool gl_frontCCW;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +000095 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096 out << uniforms;
daniel@transgaming.com86487c22010-03-11 19:41:43 +000097 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +000098 "struct PS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099 "{\n";
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000100 out << varyingInput;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000101 out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000102 out << " float vFace : VFACE;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000103 "};\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 "\n";
105 out << varyingGlobals;
106 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000107 "struct PS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108 "{\n"
109 " float4 gl_Color[1] : COLOR;\n"
110 "};\n"
111 "\n"
112 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000113 "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000114 "static float2 gl_PointCoord = float2(0.5, 0.5);\n"
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000115 "static bool gl_FrontFacing = false;\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116 "\n"
117 "float4 gl_texture2D(sampler2D s, float2 t)\n"
118 "{\n"
119 " return tex2D(s, t);\n"
120 "}\n"
121 "\n"
122 "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
123 "{\n"
124 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
125 "}\n"
126 "float4 gl_texture2DBias(sampler2D s, float2 t, float bias)\n"
127 "{\n"
128 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
129 "}\n"
130 "\n"
131 "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
132 "{\n"
133 " return texCUBE(s, t);\n"
134 "}\n"
135 "\n";
136 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000137 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 {
139 TString uniforms;
140 TString attributeInput;
141 TString attributeGlobals;
142 TString varyingOutput;
143 TString varyingGlobals;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000145 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146 int semanticIndex = 0;
147
148 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
149 {
150 const TSymbol *symbol = (*namedSymbol).second;
151 const TString &name = symbol->getName();
152
153 if (symbol->isVariable())
154 {
155 const TVariable *variable = static_cast<const TVariable*>(symbol);
156 const TType &type = variable->getType();
157 TQualifier qualifier = type.getQualifier();
158
159 if (qualifier == EvqUniform)
160 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000161 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162 }
163 else if (qualifier == EvqAttribute)
164 {
165 char semantic[100];
166 sprintf(semantic, " : TEXCOORD%d", semanticIndex);
167 semanticIndex += type.isArray() ? type.getArraySize() : 1;
168
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000169 attributeInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + semantic + ";\n";
170 attributeGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 }
172 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
173 {
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000174 // Program linking depends on this exact format
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000175 varyingOutput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
176 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000178 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000180 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000182 else if (qualifier == EvqConst)
183 {
184 // Constants are repeated as literals where used
185 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186 else UNREACHABLE();
187 }
188 }
189
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000190 out << "uniform float2 gl_HalfPixelSize;\n"
191 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192 out << uniforms;
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000193 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000194 "struct VS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195 "{\n";
196 out << attributeInput;
197 out << "};\n"
198 "\n";
199 out << attributeGlobals;
200 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000201 "struct VS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 "{\n"
203 " float4 gl_Position : POSITION;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000204 " float gl_PointSize : PSIZE;\n"
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000205 " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000206 out << varyingOutput;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207 out << "};\n"
208 "\n"
209 "static float4 gl_Position = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000210 "static float gl_PointSize = float(1);\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 out << varyingGlobals;
212 out << "\n";
213 }
214
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000215 out << "struct gl_DepthRangeParameters\n"
216 "{\n"
217 " float near;\n"
218 " float far;\n"
219 " float diff;\n"
220 "};\n"
221 "\n"
222 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
223 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000224 "float vec1(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225 "{\n"
226 " return x;\n"
227 "}\n"
228 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000229 "float vec1(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230 "{\n"
231 " return xy[0];\n"
232 "}\n"
233 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000234 "float vec1(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000235 "{\n"
236 " return xyz[0];\n"
237 "}\n"
238 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000239 "float vec1(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000240 "{\n"
241 " return xyzw[0];\n"
242 "}\n"
243 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000244 "float2 vec2(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245 "{\n"
246 " return float2(x, x);\n"
247 "}\n"
248 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000249 "float2 vec2(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250 "{\n"
251 " return float2(x, y);\n"
252 "}\n"
253 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000254 "float2 vec2(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255 "{\n"
256 " return xy;\n"
257 "}\n"
258 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000259 "float2 vec2(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 "{\n"
261 " return float2(xyz[0], xyz[1]);\n"
262 "}\n"
263 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000264 "float2 vec2(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265 "{\n"
266 " return float2(xyzw[0], xyzw[1]);\n"
267 "}\n"
268 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000269 "float3 vec3(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270 "{\n"
271 " return float3(x, x, x);\n"
272 "}\n"
273 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000274 "float3 vec3(float x, float y, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000275 "{\n"
276 " return float3(x, y, z);\n"
277 "}\n"
278 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000279 "float3 vec3(float2 xy, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280 "{\n"
281 " return float3(xy[0], xy[1], z);\n"
282 "}\n"
283 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000284 "float3 vec3(float x, float2 yz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285 "{\n"
286 " return float3(x, yz[0], yz[1]);\n"
287 "}\n"
288 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000289 "float3 vec3(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 "{\n"
291 " return xyz;\n"
292 "}\n"
293 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000294 "float3 vec3(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295 "{\n"
296 " return float3(xyzw[0], xyzw[1], xyzw[2]);\n"
297 "}\n"
298 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000299 "float4 vec4(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 "{\n"
301 " return float4(x, x, x, x);\n"
302 "}\n"
303 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000304 "float4 vec4(float x, float y, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305 "{\n"
306 " return float4(x, y, z, w);\n"
307 "}\n"
308 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000309 "float4 vec4(float2 xy, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310 "{\n"
311 " return float4(xy[0], xy[1], z, w);\n"
312 "}\n"
313 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000314 "float4 vec4(float x, float2 yz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315 "{\n"
316 " return float4(x, yz[0], yz[1], w);\n"
317 "}\n"
318 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000319 "float4 vec4(float x, float y, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320 "{\n"
321 " return float4(x, y, zw[0], zw[1]);\n"
322 "}\n"
323 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000324 "float4 vec4(float2 xy, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 "{\n"
326 " return float4(xy[0], xy[1], zw[0], zw[1]);\n"
327 "}\n"
328 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000329 "float4 vec4(float3 xyz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 "{\n"
331 " return float4(xyz[0], xyz[1], xyz[2], w);\n"
332 "}\n"
333 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000334 "float4 vec4(float x, float3 yzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335 "{\n"
336 " return float4(x, yzw[0], yzw[1], yzw[2]);\n"
337 "}\n"
338 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000339 "float4 vec4(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340 "{\n"
341 " return xyzw;\n"
342 "}\n"
343 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000344 "bool xor(bool p, bool q)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 "{\n"
346 " return (p || q) && !(p && q);\n"
347 "}\n"
348 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000349 "float mod(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000350 "{\n"
351 " return x - y * floor(x / y);\n"
352 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000353 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000354 "float2 mod(float2 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 "{\n"
356 " return x - y * floor(x / y);\n"
357 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000358 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000359 "float3 mod(float3 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360 "{\n"
361 " return x - y * floor(x / y);\n"
362 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000363 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000364 "float4 mod(float4 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365 "{\n"
366 " return x - y * floor(x / y);\n"
367 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000368 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000369 "float faceforward(float N, float I, float Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000370 "{\n"
371 " if(dot(Nref, I) < 0)\n"
372 " {\n"
373 " return N;\n"
374 " }\n"
375 " else\n"
376 " {\n"
377 " return -N;\n"
378 " }\n"
379 "}\n"
380 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000381 "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000382 "{\n"
383 " if(dot(Nref, I) < 0)\n"
384 " {\n"
385 " return N;\n"
386 " }\n"
387 " else\n"
388 " {\n"
389 " return -N;\n"
390 " }\n"
391 "}\n"
392 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000393 "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000394 "{\n"
395 " if(dot(Nref, I) < 0)\n"
396 " {\n"
397 " return N;\n"
398 " }\n"
399 " else\n"
400 " {\n"
401 " return -N;\n"
402 " }\n"
403 "}\n"
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000404 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000405 "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000406 "{\n"
407 " if(dot(Nref, I) < 0)\n"
408 " {\n"
409 " return N;\n"
410 " }\n"
411 " else\n"
412 " {\n"
413 " return -N;\n"
414 " }\n"
415 "}\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416 "\n";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000417
418 if (mUsesEqualMat2)
419 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000420 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000421 "{\n"
422 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
423 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
424 "}\n";
425 }
426
427 if (mUsesEqualMat3)
428 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000429 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000430 "{\n"
431 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
432 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
433 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
434 "}\n";
435 }
436
437 if (mUsesEqualMat4)
438 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000439 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000440 "{\n"
441 " 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"
442 " 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"
443 " 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"
444 " 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"
445 "}\n";
446 }
447
448 if (mUsesEqualVec2)
449 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000450 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000451 "{\n"
452 " return v.x == u.x && v.y == u.y;\n"
453 "}\n";
454 }
455
456 if (mUsesEqualVec3)
457 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000458 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000459 "{\n"
460 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
461 "}\n";
462 }
463
464 if (mUsesEqualVec4)
465 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000466 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000467 "{\n"
468 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
469 "}\n";
470 }
471
472 if (mUsesEqualIVec2)
473 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000474 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000475 "{\n"
476 " return v.x == u.x && v.y == u.y;\n"
477 "}\n";
478 }
479
480 if (mUsesEqualIVec3)
481 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000482 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000483 "{\n"
484 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
485 "}\n";
486 }
487
488 if (mUsesEqualIVec4)
489 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000490 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000491 "{\n"
492 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
493 "}\n";
494 }
495
496 if (mUsesEqualBVec2)
497 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000498 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000499 "{\n"
500 " return v.x == u.x && v.y == u.y;\n"
501 "}\n";
502 }
503
504 if (mUsesEqualBVec3)
505 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000506 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000507 "{\n"
508 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
509 "}\n";
510 }
511
512 if (mUsesEqualBVec4)
513 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000514 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000515 "{\n"
516 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
517 "}\n";
518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519}
520
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000521void OutputHLSL::footer()
522{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000523 EShLanguage language = mContext.language;
524 TInfoSinkBase &out = mFooter;
525 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000526
527 if (language == EShLangFragment)
528 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000529 out << "PS_OUTPUT main(PS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000530 "{\n"
531 " float rhw = 1.0 / input.gl_FragCoord.w;\n"
532 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * gl_Window.x + gl_Window.z;\n"
533 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * gl_Window.y + gl_Window.w;\n"
534 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * gl_Depth.x + gl_Depth.y;\n"
535 " gl_FragCoord.w = rhw;\n"
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000536 " gl_FrontFacing = gl_frontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0);\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000537
538 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
539 {
540 const TSymbol *symbol = (*namedSymbol).second;
541 const TString &name = symbol->getName();
542
543 if (symbol->isVariable())
544 {
545 const TVariable *variable = static_cast<const TVariable*>(symbol);
546 const TType &type = variable->getType();
547 TQualifier qualifier = type.getQualifier();
548
549 if (qualifier == EvqVaryingIn)
550 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000551 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000552 }
553 }
554 }
555
556 out << "\n"
557 " gl_main();\n"
558 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000559 " PS_OUTPUT output;\n"
560 " output.gl_Color[0] = gl_Color[0];\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000561 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000562 else // Vertex shader
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000563 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000564 out << "VS_OUTPUT main(VS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000565 "{\n";
566
567 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
568 {
569 const TSymbol *symbol = (*namedSymbol).second;
570 const TString &name = symbol->getName();
571
572 if (symbol->isVariable())
573 {
574 const TVariable *variable = static_cast<const TVariable*>(symbol);
575 const TType &type = variable->getType();
576 TQualifier qualifier = type.getQualifier();
577
578 if (qualifier == EvqAttribute)
579 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000580 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000581 }
582 }
583 }
584
585 out << "\n"
586 " gl_main();\n"
587 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000588 " VS_OUTPUT output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000589 " output.gl_Position.x = gl_Position.x - gl_HalfPixelSize.x * gl_Position.w;\n"
590 " output.gl_Position.y = -(gl_Position.y - gl_HalfPixelSize.y * gl_Position.w);\n"
591 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
592 " output.gl_Position.w = gl_Position.w;\n"
593 " output.gl_PointSize = gl_PointSize;\n"
594 " output.gl_FragCoord = gl_Position;\n";
595
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000596 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000597
598 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
599 {
600 const TSymbol *symbol = (*namedSymbol).second;
601 const TString &name = symbol->getName();
602
603 if (symbol->isVariable())
604 {
605 const TVariable *variable = static_cast<const TVariable*>(symbol);
606 TQualifier qualifier = variable->getType().getQualifier();
607
608 if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
609 {
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000610 // Program linking depends on this exact format
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000611 out << " output." + decorate(name) + " = " + decorate(name) + ";\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000612 }
613 }
614 }
615 }
616
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000617 out << " return output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000618 "}\n";
619}
620
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621void OutputHLSL::visitSymbol(TIntermSymbol *node)
622{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000623 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624
625 TString name = node->getSymbol();
626
627 if (name == "gl_FragColor")
628 {
629 out << "gl_Color[0]";
630 }
631 else if (name == "gl_FragData")
632 {
633 out << "gl_Color";
634 }
635 else
636 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000637 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000638 }
639}
640
641bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
642{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000643 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644
645 switch (node->getOp())
646 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000647 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
648 case EOpInitialize: outputTriplet(visit, NULL, " = ", NULL); break;
649 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
650 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
651 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
652 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
653 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
654 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000655 if (visit == PreVisit)
656 {
657 out << "(";
658 }
659 else if (visit == InVisit)
660 {
661 out << " = mul(";
662 node->getLeft()->traverse(this);
663 out << ", transpose(";
664 }
665 else
666 {
667 out << "))";
668 }
669 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000670 case EOpMatrixTimesMatrixAssign:
671 if (visit == PreVisit)
672 {
673 out << "(";
674 }
675 else if (visit == InVisit)
676 {
677 out << " = mul(";
678 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000679 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000680 }
681 else
682 {
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000683 out << ")";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000684 }
685 break;
686 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
687 case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break;
688 case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break;
689 case EOpIndexDirectStruct: outputTriplet(visit, NULL, ".", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000690 case EOpVectorSwizzle:
691 if (visit == InVisit)
692 {
693 out << ".";
694
695 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
696
697 if (swizzle)
698 {
699 TIntermSequence &sequence = swizzle->getSequence();
700
701 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
702 {
703 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
704
705 if (element)
706 {
707 int i = element->getUnionArrayPointer()[0].getIConst();
708
709 switch (i)
710 {
711 case 0: out << "x"; break;
712 case 1: out << "y"; break;
713 case 2: out << "z"; break;
714 case 3: out << "w"; break;
715 default: UNREACHABLE();
716 }
717 }
718 else UNREACHABLE();
719 }
720 }
721 else UNREACHABLE();
722
723 return false; // Fully processed
724 }
725 break;
726 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
727 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
728 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
729 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000730 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000731 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000732 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000733 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000734 if (node->getOp() == EOpEqual)
735 {
736 outputTriplet(visit, "(", " == ", ")");
737 }
738 else
739 {
740 outputTriplet(visit, "(", " != ", ")");
741 }
742 }
743 else if (node->getLeft()->getBasicType() == EbtStruct)
744 {
745 if (node->getOp() == EOpEqual)
746 {
747 out << "(";
748 }
749 else
750 {
751 out << "!(";
752 }
753
754 const TTypeList *fields = node->getLeft()->getType().getStruct();
755
756 for (size_t i = 0; i < fields->size(); i++)
757 {
758 const TType *fieldType = (*fields)[i].type;
759
760 node->getLeft()->traverse(this);
761 out << "." + fieldType->getFieldName() + " == ";
762 node->getRight()->traverse(this);
763 out << "." + fieldType->getFieldName();
764
765 if (i < fields->size() - 1)
766 {
767 out << " && ";
768 }
769 }
770
771 out << ")";
772
773 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000774 }
775 else
776 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000777 if (node->getLeft()->isMatrix())
778 {
779 switch (node->getLeft()->getSize())
780 {
781 case 2 * 2: mUsesEqualMat2 = true; break;
782 case 3 * 3: mUsesEqualMat3 = true; break;
783 case 4 * 4: mUsesEqualMat4 = true; break;
784 default: UNREACHABLE();
785 }
786 }
787 else if (node->getLeft()->isVector())
788 {
789 switch (node->getLeft()->getBasicType())
790 {
791 case EbtFloat:
792 switch (node->getLeft()->getSize())
793 {
794 case 2: mUsesEqualVec2 = true; break;
795 case 3: mUsesEqualVec3 = true; break;
796 case 4: mUsesEqualVec4 = true; break;
797 default: UNREACHABLE();
798 }
799 break;
800 case EbtInt:
801 switch (node->getLeft()->getSize())
802 {
803 case 2: mUsesEqualIVec2 = true; break;
804 case 3: mUsesEqualIVec3 = true; break;
805 case 4: mUsesEqualIVec4 = true; break;
806 default: UNREACHABLE();
807 }
808 break;
809 case EbtBool:
810 switch (node->getLeft()->getSize())
811 {
812 case 2: mUsesEqualBVec2 = true; break;
813 case 3: mUsesEqualBVec3 = true; break;
814 case 4: mUsesEqualBVec4 = true; break;
815 default: UNREACHABLE();
816 }
817 break;
818 default: UNREACHABLE();
819 }
820 }
821 else UNREACHABLE();
822
823 if (node->getOp() == EOpEqual)
824 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000825 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000826 }
827 else
828 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000829 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000830 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000831 }
832 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000833 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
834 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
835 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
836 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
837 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000838 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000839 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
840 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
841 case EOpMatrixTimesMatrix: outputTriplet(visit, "mul(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000842 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000843 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
845 default: UNREACHABLE();
846 }
847
848 return true;
849}
850
851bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
852{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000853 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000854
855 switch (node->getOp())
856 {
857 case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break;
858 case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
859 case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000860 case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break;
861 case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break;
862 case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break;
863 case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break;
864 case EOpConvIntToBool:
865 case EOpConvFloatToBool:
866 switch (node->getOperand()->getType().getNominalSize())
867 {
868 case 1: outputTriplet(visit, "bool(", NULL, ")"); break;
869 case 2: outputTriplet(visit, "bool2(", NULL, ")"); break;
870 case 3: outputTriplet(visit, "bool3(", NULL, ")"); break;
871 case 4: outputTriplet(visit, "bool4(", NULL, ")"); break;
872 default: UNREACHABLE();
873 }
874 break;
875 case EOpConvBoolToFloat:
876 case EOpConvIntToFloat:
877 switch (node->getOperand()->getType().getNominalSize())
878 {
879 case 1: outputTriplet(visit, "float(", NULL, ")"); break;
880 case 2: outputTriplet(visit, "float2(", NULL, ")"); break;
881 case 3: outputTriplet(visit, "float3(", NULL, ")"); break;
882 case 4: outputTriplet(visit, "float4(", NULL, ")"); break;
883 default: UNREACHABLE();
884 }
885 break;
886 case EOpConvFloatToInt:
887 case EOpConvBoolToInt:
888 switch (node->getOperand()->getType().getNominalSize())
889 {
890 case 1: outputTriplet(visit, "int(", NULL, ")"); break;
891 case 2: outputTriplet(visit, "int2(", NULL, ")"); break;
892 case 3: outputTriplet(visit, "int3(", NULL, ")"); break;
893 case 4: outputTriplet(visit, "int4(", NULL, ")"); break;
894 default: UNREACHABLE();
895 }
896 break;
897 case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break;
898 case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break;
899 case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break;
900 case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break;
901 case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break;
902 case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break;
903 case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break;
904 case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break;
905 case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break;
906 case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break;
907 case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break;
908 case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break;
909 case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break;
910 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break;
911 case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break;
912 case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break;
913 case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break;
914 case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break;
915 case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break;
916 case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break;
917 case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break;
daniel@transgaming.com45d03582010-03-11 19:41:29 +0000918// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break;
919// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break;
920// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921 case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break;
922 case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break;
923 default: UNREACHABLE();
924 }
925
926 return true;
927}
928
929bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
930{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000931 EShLanguage language = mContext.language;
932 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000934 switch (node->getOp())
935 {
936 case EOpSequence: outputTriplet(visit, NULL, ";\n", ";\n"); break;
937 case EOpDeclaration:
938 if (visit == PreVisit)
939 {
940 TIntermSequence &sequence = node->getSequence();
941 TIntermTyped *variable = sequence[0]->getAsTyped();
942 bool visit = true;
943
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000944 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000946 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000948 if (variable->getQualifier() == EvqGlobal)
949 {
950 out << "static ";
951 }
952
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000953 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000955 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000956 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000957 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000958
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000959 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000961 symbol->traverse(this);
962
963 out << arrayString(symbol->getType());
964 }
965 else
966 {
967 (*sit)->traverse(this);
968 }
969
970 if (visit && this->inVisit)
971 {
972 if (*sit != sequence.back())
973 {
974 visit = this->visitAggregate(InVisit, node);
975 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000976 }
977 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000979 if (visit && this->postVisit)
980 {
981 this->visitAggregate(PostVisit, node);
982 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000983 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000984 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
985 {
986 const TType &type = variable->getType();
987 const TTypeList &fields = *type.getStruct();
988
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000989 out << "struct " + decorate(type.getTypeName()) + "\n"
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000990 "{\n";
991
992 for (unsigned int i = 0; i < fields.size(); i++)
993 {
994 const TType &field = *fields[i].type;
995
996 out << " " + typeString(field) + " " + field.getFieldName() + ";\n";
997 }
998
999 out << "};\n";
1000 }
1001 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001002 }
1003
1004 return false;
1005 }
1006 else if (visit == InVisit)
1007 {
1008 out << ", ";
1009 }
1010 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001011 case EOpPrototype:
1012 if (visit == PreVisit)
1013 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001014 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001015
1016 TIntermSequence &arguments = node->getSequence();
1017
1018 for (unsigned int i = 0; i < arguments.size(); i++)
1019 {
1020 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1021
1022 if (symbol)
1023 {
1024 out << argumentString(symbol);
1025
1026 if (i < arguments.size() - 1)
1027 {
1028 out << ", ";
1029 }
1030 }
1031 else UNREACHABLE();
1032 }
1033
1034 out << ");\n";
1035
1036 return false;
1037 }
1038 break;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001039 case EOpComma: outputTriplet(visit, NULL, ", ", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001040 case EOpFunction:
1041 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001042 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043
1044 if (visit == PreVisit)
1045 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001046 out << typeString(node->getType()) << " ";
1047
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001048 if (name == "main")
1049 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001050 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001051 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001052 else
1053 {
1054 out << decorate(name) << "(";
1055 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001056
1057 TIntermSequence &sequence = node->getSequence();
1058 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1059
1060 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001062 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001064 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001066 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001067
1068 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001070 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001071 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001073 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001075
1076 sequence.erase(sequence.begin());
1077
1078 out << ")\n"
1079 "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080 }
1081 else if (visit == PostVisit)
1082 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001083 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 }
1085 }
1086 break;
1087 case EOpFunctionCall:
1088 {
1089 if (visit == PreVisit)
1090 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001091 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092
1093 if (node->isUserDefined())
1094 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001095 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 }
1097 else
1098 {
1099 if (name == "texture2D")
1100 {
1101 if (node->getSequence().size() == 2)
1102 {
1103 out << "gl_texture2D(";
1104 }
1105 else if (node->getSequence().size() == 3)
1106 {
1107 out << "gl_texture2DBias(";
1108 }
1109 else UNREACHABLE();
1110 }
1111 else if (name == "texture2DProj")
1112 {
1113 out << "gl_texture2DProj(";
1114 }
1115 else if (name == "texture2DLod")
1116 {
1117 out << "gl_texture2DLod(";
1118 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1119 }
1120 else if (name == "texture2DProjLod")
1121 {
1122 out << "gl_texture2DProjLod(";
1123 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1124 }
1125 else if (name == "textureCube")
1126 {
1127 out << "gl_textureCube("; // FIXME: Incorrect sampling location
1128 }
1129 else
1130 {
1131 UNIMPLEMENTED(); // FIXME
1132 }
1133 }
1134 }
1135 else if (visit == InVisit)
1136 {
1137 out << ", ";
1138 }
1139 else
1140 {
1141 out << ")";
1142 }
1143 }
1144 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001145 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1146 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1147 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1148 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1149 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1151 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1152 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1153 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1154 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1155 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1156 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1157 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001158 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1159 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1160 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1161 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1162 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1163 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1164 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1165 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1166 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1167 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001168 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001169 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001170 case EOpAtan:
1171 if (node->getSequence().size() == 1)
1172 {
1173 outputTriplet(visit, "atan(", ", ", ")");
1174 }
1175 else if (node->getSequence().size() == 2)
1176 {
1177 outputTriplet(visit, "atan2(", ", ", ")");
1178 }
1179 else UNREACHABLE();
1180 break;
1181 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1182 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1183 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1184 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1185 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1186 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1187 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1188 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1189 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com680553b2010-03-08 21:30:52 +00001190 case EOpFaceForward: outputTriplet(visit, "faceforward(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001191 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1192 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1193 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001194 default: UNREACHABLE();
1195 }
1196
1197 return true;
1198}
1199
1200bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1201{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001202 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001204 if (node->usesTernaryOperator())
1205 {
1206 out << "(";
1207 node->getCondition()->traverse(this);
1208 out << ") ? (";
1209 node->getTrueBlock()->traverse(this);
1210 out << ") : (";
1211 node->getFalseBlock()->traverse(this);
1212 out << ")\n";
1213 }
1214 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215 {
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001216 out << "if(";
1217
1218 node->getCondition()->traverse(this);
1219
1220 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221 "{\n";
1222
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001223 node->getTrueBlock()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001224
1225 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001226
1227 if (node->getFalseBlock())
1228 {
1229 out << "else\n"
1230 "{\n";
1231
1232 node->getFalseBlock()->traverse(this);
1233
1234 out << ";}\n";
1235 }
1236 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001237
1238 return false;
1239}
1240
1241void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1242{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001243 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001244
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001245 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001246
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001247 if (type.isField())
1248 {
1249 out << type.getFieldName();
1250 }
1251 else
1252 {
1253 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001254
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001255 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001256 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001257 out << "{";
1258 }
1259 else
1260 {
1261 bool matrix = type.isMatrix();
1262 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1263
1264 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001265 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001266 case EbtBool:
1267 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001268 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001269 switch (size)
1270 {
1271 case 1: out << "bool("; break;
1272 case 2: out << "bool2("; break;
1273 case 3: out << "bool3("; break;
1274 case 4: out << "bool4("; break;
1275 default: UNREACHABLE();
1276 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001277 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001278 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001279 break;
1280 case EbtFloat:
1281 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001282 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001283 switch (size)
1284 {
1285 case 1: out << "float("; break;
1286 case 2: out << "float2("; break;
1287 case 3: out << "float3("; break;
1288 case 4: out << "float4("; break;
1289 default: UNREACHABLE();
1290 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001291 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001292 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001293 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001294 switch (size)
1295 {
1296 case 4: out << "float2x2("; break;
1297 case 9: out << "float3x3("; break;
1298 case 16: out << "float4x4("; break;
1299 default: UNREACHABLE();
1300 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001301 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001302 break;
1303 case EbtInt:
1304 if (!matrix)
1305 {
1306 switch (size)
1307 {
1308 case 1: out << "int("; break;
1309 case 2: out << "int2("; break;
1310 case 3: out << "int3("; break;
1311 case 4: out << "int4("; break;
1312 default: UNREACHABLE();
1313 }
1314 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001315 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001316 break;
1317 default:
1318 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001319 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001320 }
1321
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001322 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001323 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001324 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001325 {
1326 case EbtBool:
1327 if (node->getUnionArrayPointer()[i].getBConst())
1328 {
1329 out << "true";
1330 }
1331 else
1332 {
1333 out << "false";
1334 }
1335 break;
1336 case EbtFloat:
1337 out << node->getUnionArrayPointer()[i].getFConst();
1338 break;
1339 case EbtInt:
1340 out << node->getUnionArrayPointer()[i].getIConst();
1341 break;
1342 default:
1343 UNIMPLEMENTED(); // FIXME
1344 }
1345
1346 if (i != size - 1)
1347 {
1348 out << ", ";
1349 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001350 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001351
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001352 if (type.getBasicType() == EbtStruct)
1353 {
1354 out << "}";
1355 }
1356 else
1357 {
1358 out << ")";
1359 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001360 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001361}
1362
1363bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1364{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001365 if (handleExcessiveLoop(node))
1366 {
1367 return false;
1368 }
1369
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001370 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001371
1372 if (!node->testFirst())
1373 {
1374 out << "do\n"
1375 "{\n";
1376 }
1377 else
1378 {
1379 out << "for(";
1380
1381 if (node->getInit())
1382 {
1383 node->getInit()->traverse(this);
1384 }
1385
1386 out << "; ";
1387
1388 if (node->getTest())
1389 {
1390 node->getTest()->traverse(this);
1391 }
1392
1393 out << "; ";
1394
1395 if (node->getTerminal())
1396 {
1397 node->getTerminal()->traverse(this);
1398 }
1399
1400 out << ")\n"
1401 "{\n";
1402 }
1403
1404 if (node->getBody())
1405 {
1406 node->getBody()->traverse(this);
1407 }
1408
1409 out << "}\n";
1410
1411 if (!node->testFirst())
1412 {
1413 out << "while(\n";
1414
1415 node->getTest()->traverse(this);
1416
1417 out << ")";
1418 }
1419
1420 out << ";\n";
1421
1422 return false;
1423}
1424
1425bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1426{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001427 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001428
1429 switch (node->getFlowOp())
1430 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001431 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1432 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1433 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001434 case EOpReturn:
1435 if (visit == PreVisit)
1436 {
1437 if (node->getExpression())
1438 {
1439 out << "return ";
1440 }
1441 else
1442 {
1443 out << "return;\n";
1444 }
1445 }
1446 else if (visit == PostVisit)
1447 {
1448 out << ";\n";
1449 }
1450 break;
1451 default: UNREACHABLE();
1452 }
1453
1454 return true;
1455}
1456
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001457// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1458bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1459{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001460 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001461
1462 // Parse loops of the form:
1463 // for(int index = initial; index [comparator] limit; index += increment)
1464 TIntermSymbol *index = NULL;
1465 TOperator comparator = EOpNull;
1466 int initial = 0;
1467 int limit = 0;
1468 int increment = 0;
1469
1470 // Parse index name and intial value
1471 if (node->getInit())
1472 {
1473 TIntermAggregate *init = node->getInit()->getAsAggregate();
1474
1475 if (init)
1476 {
1477 TIntermSequence &sequence = init->getSequence();
1478 TIntermTyped *variable = sequence[0]->getAsTyped();
1479
1480 if (variable && variable->getQualifier() == EvqTemporary)
1481 {
1482 TIntermBinary *assign = variable->getAsBinaryNode();
1483
1484 if (assign->getOp() == EOpInitialize)
1485 {
1486 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1487 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1488
1489 if (symbol && constant)
1490 {
1491 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1492 {
1493 index = symbol;
1494 initial = constant->getUnionArrayPointer()[0].getIConst();
1495 }
1496 }
1497 }
1498 }
1499 }
1500 }
1501
1502 // Parse comparator and limit value
1503 if (index != NULL && node->getTest())
1504 {
1505 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1506
1507 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1508 {
1509 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1510
1511 if (constant)
1512 {
1513 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1514 {
1515 comparator = test->getOp();
1516 limit = constant->getUnionArrayPointer()[0].getIConst();
1517 }
1518 }
1519 }
1520 }
1521
1522 // Parse increment
1523 if (index != NULL && comparator != EOpNull && node->getTerminal())
1524 {
1525 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1526 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1527
1528 if (binaryTerminal)
1529 {
1530 TOperator op = binaryTerminal->getOp();
1531 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1532
1533 if (constant)
1534 {
1535 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1536 {
1537 int value = constant->getUnionArrayPointer()[0].getIConst();
1538
1539 switch (op)
1540 {
1541 case EOpAddAssign: increment = value; break;
1542 case EOpSubAssign: increment = -value; break;
1543 default: UNIMPLEMENTED();
1544 }
1545 }
1546 }
1547 }
1548 else if (unaryTerminal)
1549 {
1550 TOperator op = unaryTerminal->getOp();
1551
1552 switch (op)
1553 {
1554 case EOpPostIncrement: increment = 1; break;
1555 case EOpPostDecrement: increment = -1; break;
1556 case EOpPreIncrement: increment = 1; break;
1557 case EOpPreDecrement: increment = -1; break;
1558 default: UNIMPLEMENTED();
1559 }
1560 }
1561 }
1562
1563 if (index != NULL && comparator != EOpNull && increment != 0)
1564 {
1565 if (comparator == EOpLessThanEqual)
1566 {
1567 comparator = EOpLessThan;
1568 limit += 1;
1569 }
1570
1571 if (comparator == EOpLessThan)
1572 {
1573 int iterations = (limit - initial + 1) / increment;
1574
1575 if (iterations <= 255)
1576 {
1577 return false; // Not an excessive loop
1578 }
1579
1580 while (iterations > 0)
1581 {
1582 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001583 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001584
1585 // for(int index = initial; index < clampedLimit; index += increment)
1586
1587 out << "for(int ";
1588 index->traverse(this);
1589 out << " = ";
1590 out << initial;
1591
1592 out << "; ";
1593 index->traverse(this);
1594 out << " < ";
1595 out << clampedLimit;
1596
1597 out << "; ";
1598 index->traverse(this);
1599 out << " += ";
1600 out << increment;
1601 out << ")\n"
1602 "{\n";
1603
1604 if (node->getBody())
1605 {
1606 node->getBody()->traverse(this);
1607 }
1608
1609 out << "}\n";
1610
1611 initial += 255 * increment;
1612 iterations -= 255;
1613 }
1614
1615 return true;
1616 }
1617 else UNIMPLEMENTED();
1618 }
1619
1620 return false; // Not handled as an excessive loop
1621}
1622
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001623void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1624{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001625 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001626
1627 if (visit == PreVisit && preString)
1628 {
1629 out << preString;
1630 }
1631 else if (visit == InVisit && inString)
1632 {
1633 out << inString;
1634 }
1635 else if (visit == PostVisit && postString)
1636 {
1637 out << postString;
1638 }
1639}
1640
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001641TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1642{
1643 TQualifier qualifier = symbol->getQualifier();
1644 const TType &type = symbol->getType();
1645 const TString &name = symbol->getSymbol();
1646
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001647 return qualifierString(qualifier) + " " + typeString(type) + " " + decorate(name) + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001648}
1649
1650TString OutputHLSL::qualifierString(TQualifier qualifier)
1651{
1652 switch(qualifier)
1653 {
1654 case EvqIn: return "in";
1655 case EvqOut: return "out";
1656 case EvqInOut: return "inout";
1657 case EvqConstReadOnly: return "const";
1658 default: UNREACHABLE();
1659 }
1660
1661 return "";
1662}
1663
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001664TString OutputHLSL::typeString(const TType &type)
1665{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001666 if (type.getBasicType() == EbtStruct)
1667 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001668 return decorate(type.getTypeName());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001669 }
1670 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001671 {
1672 switch (type.getNominalSize())
1673 {
1674 case 2: return "float2x2";
1675 case 3: return "float3x3";
1676 case 4: return "float4x4";
1677 }
1678 }
1679 else
1680 {
1681 switch (type.getBasicType())
1682 {
1683 case EbtFloat:
1684 switch (type.getNominalSize())
1685 {
1686 case 1: return "float";
1687 case 2: return "float2";
1688 case 3: return "float3";
1689 case 4: return "float4";
1690 }
1691 case EbtInt:
1692 switch (type.getNominalSize())
1693 {
1694 case 1: return "int";
1695 case 2: return "int2";
1696 case 3: return "int3";
1697 case 4: return "int4";
1698 }
1699 case EbtBool:
1700 switch (type.getNominalSize())
1701 {
1702 case 1: return "bool";
1703 case 2: return "bool2";
1704 case 3: return "bool3";
1705 case 4: return "bool4";
1706 }
1707 case EbtVoid:
1708 return "void";
1709 case EbtSampler2D:
1710 return "sampler2D";
1711 case EbtSamplerCube:
1712 return "samplerCUBE";
1713 }
1714 }
1715
1716 UNIMPLEMENTED(); // FIXME
1717 return "<unknown type>";
1718}
1719
1720TString OutputHLSL::arrayString(const TType &type)
1721{
1722 if (!type.isArray())
1723 {
1724 return "";
1725 }
1726
1727 char buffer[100];
1728 sprintf(buffer, "[%d]", type.getArraySize());
1729
1730 return buffer;
1731}
1732
1733TString OutputHLSL::initializer(const TType &type)
1734{
1735 TString string;
1736
1737 int arraySize = type.isArray() ? type.getArraySize() : 1;
1738
1739 if (type.isArray())
1740 {
1741 string += "{";
1742 }
1743
1744 for (int element = 0; element < arraySize; element++)
1745 {
1746 string += typeString(type) + "(";
1747
1748 for (int component = 0; component < type.getNominalSize(); component++)
1749 {
1750 string += "0";
1751
1752 if (component < type.getNominalSize() - 1)
1753 {
1754 string += ", ";
1755 }
1756 }
1757
1758 string += ")";
1759
1760 if (element < arraySize - 1)
1761 {
1762 string += ", ";
1763 }
1764 }
1765
1766 if (type.isArray())
1767 {
1768 string += "}";
1769 }
1770
1771 return string;
1772}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001773
1774TString OutputHLSL::decorate(const TString &string)
1775{
1776 if (string.substr(0, 3) != "gl_")
1777 {
1778 return "_" + string;
1779 }
1780 else
1781 {
1782 return string;
1783 }
1784}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785}