blob: 0d3af2c0eaf5f52ce70f3a6ef6bce9d48f90ebf4 [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 {
68 uniforms += "uniform " + typeString(type) + " " + name + arrayString(type) + ";\n";
69 }
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.com4f39fd92010-03-08 20:26:45 +000077 varyingInput += " " + typeString(type) + " " + name + arrayString(type) + semantic + ";\n";
78 varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n";
79 }
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.com79b820b2010-03-16 05:48:57 +000094 "uniform bool __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"
98 "struct PS_INPUT\n" // FIXME: Prevent name clashes
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.com79b820b2010-03-16 05:48:57 +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"
107 "struct PS_OUTPUT\n" // FIXME: Prevent name clashes
108 "{\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 {
161 uniforms += "uniform " + typeString(type) + " " + name + arrayString(type) + ";\n";
162 }
163 else if (qualifier == EvqAttribute)
164 {
165 char semantic[100];
166 sprintf(semantic, " : TEXCOORD%d", semanticIndex);
167 semanticIndex += type.isArray() ? type.getArraySize() : 1;
168
169 attributeInput += " " + typeString(type) + " " + name + arrayString(type) + semantic + ";\n";
170 attributeGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n";
171 }
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.com4f39fd92010-03-08 20:26:45 +0000175 varyingOutput += " " + typeString(type) + " " + name + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
176 varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n";
177 }
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"
194 "struct VS_INPUT\n" // FIXME: Prevent name clashes
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195 "{\n";
196 out << attributeInput;
197 out << "};\n"
198 "\n";
199 out << attributeGlobals;
200 out << "\n"
201 "struct VS_OUTPUT\n" // FIXME: Prevent name clashes
202 "{\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"
224 "float vec1(float x)\n" // FIXME: Prevent name clashes
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225 "{\n"
226 " return x;\n"
227 "}\n"
228 "\n"
229 "float vec1(float2 xy)\n" // FIXME: Prevent name clashes
230 "{\n"
231 " return xy[0];\n"
232 "}\n"
233 "\n"
234 "float vec1(float3 xyz)\n" // FIXME: Prevent name clashes
235 "{\n"
236 " return xyz[0];\n"
237 "}\n"
238 "\n"
239 "float vec1(float4 xyzw)\n" // FIXME: Prevent name clashes
240 "{\n"
241 " return xyzw[0];\n"
242 "}\n"
243 "\n"
244 "float2 vec2(float x)\n" // FIXME: Prevent name clashes
245 "{\n"
246 " return float2(x, x);\n"
247 "}\n"
248 "\n"
249 "float2 vec2(float x, float y)\n" // FIXME: Prevent name clashes
250 "{\n"
251 " return float2(x, y);\n"
252 "}\n"
253 "\n"
254 "float2 vec2(float2 xy)\n" // FIXME: Prevent name clashes
255 "{\n"
256 " return xy;\n"
257 "}\n"
258 "\n"
259 "float2 vec2(float3 xyz)\n" // FIXME: Prevent name clashes
260 "{\n"
261 " return float2(xyz[0], xyz[1]);\n"
262 "}\n"
263 "\n"
264 "float2 vec2(float4 xyzw)\n" // FIXME: Prevent name clashes
265 "{\n"
266 " return float2(xyzw[0], xyzw[1]);\n"
267 "}\n"
268 "\n"
269 "float3 vec3(float x)\n" // FIXME: Prevent name clashes
270 "{\n"
271 " return float3(x, x, x);\n"
272 "}\n"
273 "\n"
274 "float3 vec3(float x, float y, float z)\n" // FIXME: Prevent name clashes
275 "{\n"
276 " return float3(x, y, z);\n"
277 "}\n"
278 "\n"
279 "float3 vec3(float2 xy, float z)\n" // FIXME: Prevent name clashes
280 "{\n"
281 " return float3(xy[0], xy[1], z);\n"
282 "}\n"
283 "\n"
284 "float3 vec3(float x, float2 yz)\n" // FIXME: Prevent name clashes
285 "{\n"
286 " return float3(x, yz[0], yz[1]);\n"
287 "}\n"
288 "\n"
289 "float3 vec3(float3 xyz)\n" // FIXME: Prevent name clashes
290 "{\n"
291 " return xyz;\n"
292 "}\n"
293 "\n"
294 "float3 vec3(float4 xyzw)\n" // FIXME: Prevent name clashes
295 "{\n"
296 " return float3(xyzw[0], xyzw[1], xyzw[2]);\n"
297 "}\n"
298 "\n"
299 "float4 vec4(float x)\n" // FIXME: Prevent name clashes
300 "{\n"
301 " return float4(x, x, x, x);\n"
302 "}\n"
303 "\n"
304 "float4 vec4(float x, float y, float z, float w)\n" // FIXME: Prevent name clashes
305 "{\n"
306 " return float4(x, y, z, w);\n"
307 "}\n"
308 "\n"
309 "float4 vec4(float2 xy, float z, float w)\n" // FIXME: Prevent name clashes
310 "{\n"
311 " return float4(xy[0], xy[1], z, w);\n"
312 "}\n"
313 "\n"
314 "float4 vec4(float x, float2 yz, float w)\n" // FIXME: Prevent name clashes
315 "{\n"
316 " return float4(x, yz[0], yz[1], w);\n"
317 "}\n"
318 "\n"
319 "float4 vec4(float x, float y, float2 zw)\n" // FIXME: Prevent name clashes
320 "{\n"
321 " return float4(x, y, zw[0], zw[1]);\n"
322 "}\n"
323 "\n"
324 "float4 vec4(float2 xy, float2 zw)\n" // FIXME: Prevent name clashes
325 "{\n"
326 " return float4(xy[0], xy[1], zw[0], zw[1]);\n"
327 "}\n"
328 "\n"
329 "float4 vec4(float3 xyz, float w)\n" // FIXME: Prevent name clashes
330 "{\n"
331 " return float4(xyz[0], xyz[1], xyz[2], w);\n"
332 "}\n"
333 "\n"
334 "float4 vec4(float x, float3 yzw)\n" // FIXME: Prevent name clashes
335 "{\n"
336 " return float4(x, yzw[0], yzw[1], yzw[2]);\n"
337 "}\n"
338 "\n"
339 "float4 vec4(float4 xyzw)\n" // FIXME: Prevent name clashes
340 "{\n"
341 " return xyzw;\n"
342 "}\n"
343 "\n"
344 "bool xor(bool p, bool q)\n" // FIXME: Prevent name clashes
345 "{\n"
346 " return (p || q) && !(p && q);\n"
347 "}\n"
348 "\n"
349 "float mod(float x, float y)\n" // FIXME: Prevent name clashes
350 "{\n"
351 " return x - y * floor(x / y);\n"
352 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000353 "\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 "float2 mod(float2 x, float y)\n" // FIXME: Prevent name clashes
355 "{\n"
356 " return x - y * floor(x / y);\n"
357 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000358 "\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359 "float3 mod(float3 x, float y)\n" // FIXME: Prevent name clashes
360 "{\n"
361 " return x - y * floor(x / y);\n"
362 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000363 "\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364 "float4 mod(float4 x, float y)\n" // FIXME: Prevent name clashes
365 "{\n"
366 " return x - y * floor(x / y);\n"
367 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000368 "\n"
369 "float faceforward(float N, float I, float Nref)\n" // FIXME: Prevent name clashes
370 "{\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"
381 "float2 faceforward(float2 N, float2 I, float2 Nref)\n" // FIXME: Prevent name clashes
382 "{\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"
393 "float3 faceforward(float3 N, float3 I, float3 Nref)\n" // FIXME: Prevent name clashes
394 "{\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.com680553b2010-03-08 21:30:52 +0000405 "float4 faceforward(float4 N, float4 I, float4 Nref)\n" // FIXME: Prevent name clashes
406 "{\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 {
420 out << "bool __equal(float2x2 m, float2x2 n)\n"
421 "{\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 {
429 out << "bool __equal(float3x3 m, float3x3 n)\n"
430 "{\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 {
439 out << "bool __equal(float4x4 m, float4x4 n)\n"
440 "{\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 {
450 out << "bool __equal(float2 v, float2 u)\n"
451 "{\n"
452 " return v.x == u.x && v.y == u.y;\n"
453 "}\n";
454 }
455
456 if (mUsesEqualVec3)
457 {
458 out << "bool __equal(float3 v, float3 u)\n"
459 "{\n"
460 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
461 "}\n";
462 }
463
464 if (mUsesEqualVec4)
465 {
466 out << "bool __equal(float4 v, float4 u)\n"
467 "{\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 {
474 out << "bool __equal(int2 v, int2 u)\n"
475 "{\n"
476 " return v.x == u.x && v.y == u.y;\n"
477 "}\n";
478 }
479
480 if (mUsesEqualIVec3)
481 {
482 out << "bool __equal(int3 v, int3 u)\n"
483 "{\n"
484 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
485 "}\n";
486 }
487
488 if (mUsesEqualIVec4)
489 {
490 out << "bool __equal(int4 v, int4 u)\n"
491 "{\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 {
498 out << "bool __equal(bool2 v, bool2 u)\n"
499 "{\n"
500 " return v.x == u.x && v.y == u.y;\n"
501 "}\n";
502 }
503
504 if (mUsesEqualBVec3)
505 {
506 out << "bool __equal(bool3 v, bool3 u)\n"
507 "{\n"
508 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
509 "}\n";
510 }
511
512 if (mUsesEqualBVec4)
513 {
514 out << "bool __equal(bool4 v, bool4 u)\n"
515 "{\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 {
529 out << "PS_OUTPUT main(PS_INPUT input)\n" // FIXME: Prevent name clashes
530 "{\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"
536 " gl_FrontFacing = __frontCCW ? (input.__vFace >= 0.0) : (input.__vFace <= 0.0);\n";
537
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 {
551 out << " " + name + " = input." + name + ";\n"; // FIXME: Prevent name clashes
552 }
553 }
554 }
555
556 out << "\n"
557 " gl_main();\n"
558 "\n"
559 " PS_OUTPUT output;\n" // FIXME: Prevent name clashes
560 " output.gl_Color[0] = gl_Color[0];\n"; // FIXME: Prevent name clashes
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 {
564 out << "VS_OUTPUT main(VS_INPUT input)\n" // FIXME: Prevent name clashes
565 "{\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 {
580 out << " " + name + " = input." + name + ";\n"; // FIXME: Prevent name clashes
581 }
582 }
583 }
584
585 out << "\n"
586 " gl_main();\n"
587 "\n"
588 " VS_OUTPUT output;\n" // FIXME: Prevent name clashes
589 " 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.come78c0c92010-03-28 19:36:06 +0000611 out << " output." + name + " = " + name + ";\n"; // FIXME: Prevent name clashes
612 }
613 }
614 }
615 }
616
617 out << " return output;\n" // FIXME: Prevent name clashes
618 "}\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 {
637 out << name;
638 }
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:
655 case EOpMatrixTimesMatrixAssign:
656 if (visit == PreVisit)
657 {
658 out << "(";
659 }
660 else if (visit == InVisit)
661 {
662 out << " = mul(";
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000663
daniel@transgaming.com5441d662010-04-07 03:25:11 +0000664 if (node->getLeft()->getQualifier() == EvqUniform)
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000665 {
666 out << "transpose(";
667 }
668
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000669 node->getLeft()->traverse(this);
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000670
daniel@transgaming.com5441d662010-04-07 03:25:11 +0000671 if (node->getLeft()->getQualifier() == EvqUniform)
daniel@transgaming.com279e38a2010-04-03 20:56:13 +0000672 {
673 out << ")";
674 }
675
daniel@transgaming.com5441d662010-04-07 03:25:11 +0000676 out << ", ";
677
678 if (node->getRight()->getQualifier() == EvqUniform)
679 {
680 out << "transpose(";
681 }
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000682 }
683 else
684 {
daniel@transgaming.com5441d662010-04-07 03:25:11 +0000685 if (node->getRight()->getQualifier() == EvqUniform)
686 {
687 out << ")";
688 }
689
690 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000691 }
692 break;
693 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
694 case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break;
695 case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break;
696 case EOpIndexDirectStruct: outputTriplet(visit, NULL, ".", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000697 case EOpVectorSwizzle:
698 if (visit == InVisit)
699 {
700 out << ".";
701
702 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
703
704 if (swizzle)
705 {
706 TIntermSequence &sequence = swizzle->getSequence();
707
708 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
709 {
710 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
711
712 if (element)
713 {
714 int i = element->getUnionArrayPointer()[0].getIConst();
715
716 switch (i)
717 {
718 case 0: out << "x"; break;
719 case 1: out << "y"; break;
720 case 2: out << "z"; break;
721 case 3: out << "w"; break;
722 default: UNREACHABLE();
723 }
724 }
725 else UNREACHABLE();
726 }
727 }
728 else UNREACHABLE();
729
730 return false; // Fully processed
731 }
732 break;
733 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
734 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
735 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
736 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000737 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000738 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000739 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000740 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000741 if (node->getOp() == EOpEqual)
742 {
743 outputTriplet(visit, "(", " == ", ")");
744 }
745 else
746 {
747 outputTriplet(visit, "(", " != ", ")");
748 }
749 }
750 else if (node->getLeft()->getBasicType() == EbtStruct)
751 {
752 if (node->getOp() == EOpEqual)
753 {
754 out << "(";
755 }
756 else
757 {
758 out << "!(";
759 }
760
761 const TTypeList *fields = node->getLeft()->getType().getStruct();
762
763 for (size_t i = 0; i < fields->size(); i++)
764 {
765 const TType *fieldType = (*fields)[i].type;
766
767 node->getLeft()->traverse(this);
768 out << "." + fieldType->getFieldName() + " == ";
769 node->getRight()->traverse(this);
770 out << "." + fieldType->getFieldName();
771
772 if (i < fields->size() - 1)
773 {
774 out << " && ";
775 }
776 }
777
778 out << ")";
779
780 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000781 }
782 else
783 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000784 if (node->getLeft()->isMatrix())
785 {
786 switch (node->getLeft()->getSize())
787 {
788 case 2 * 2: mUsesEqualMat2 = true; break;
789 case 3 * 3: mUsesEqualMat3 = true; break;
790 case 4 * 4: mUsesEqualMat4 = true; break;
791 default: UNREACHABLE();
792 }
793 }
794 else if (node->getLeft()->isVector())
795 {
796 switch (node->getLeft()->getBasicType())
797 {
798 case EbtFloat:
799 switch (node->getLeft()->getSize())
800 {
801 case 2: mUsesEqualVec2 = true; break;
802 case 3: mUsesEqualVec3 = true; break;
803 case 4: mUsesEqualVec4 = true; break;
804 default: UNREACHABLE();
805 }
806 break;
807 case EbtInt:
808 switch (node->getLeft()->getSize())
809 {
810 case 2: mUsesEqualIVec2 = true; break;
811 case 3: mUsesEqualIVec3 = true; break;
812 case 4: mUsesEqualIVec4 = true; break;
813 default: UNREACHABLE();
814 }
815 break;
816 case EbtBool:
817 switch (node->getLeft()->getSize())
818 {
819 case 2: mUsesEqualBVec2 = true; break;
820 case 3: mUsesEqualBVec3 = true; break;
821 case 4: mUsesEqualBVec4 = true; break;
822 default: UNREACHABLE();
823 }
824 break;
825 default: UNREACHABLE();
826 }
827 }
828 else UNREACHABLE();
829
830 if (node->getOp() == EOpEqual)
831 {
832 outputTriplet(visit, "__equal(", ", ", ")");
833 }
834 else
835 {
836 outputTriplet(visit, "!__equal(", ", ", ")");
837 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000838 }
839 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000840 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
841 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
842 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
843 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
844 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000845 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com5441d662010-04-07 03:25:11 +0000846 case EOpVectorTimesMatrix:
847 if (node->getRight()->getQualifier() == EvqUniform)
848 {
849 outputTriplet(visit, "mul(", ", transpose(", "))");
850 }
851 else
852 {
853 outputTriplet(visit, "mul(", ", ", ")");
854 }
855 break;
856 case EOpMatrixTimesVector:
857 if (node->getLeft()->getQualifier() == EvqUniform)
858 {
859 outputTriplet(visit, "mul(transpose(", "), ", ")");
860 }
861 else
862 {
863 outputTriplet(visit, "mul(", ", ", ")");
864 }
865 break;
866 case EOpMatrixTimesMatrix:
867 if (node->getLeft()->getQualifier() == EvqUniform)
868 {
869 if (node->getRight()->getQualifier() == EvqUniform)
870 {
871 outputTriplet(visit, "mul(transpose(", "), transpose(", "))");
872 }
873 else
874 {
875 outputTriplet(visit, "mul(transpose(", "), ", ")");
876 }
877 }
878 else
879 {
880 if (node->getRight()->getQualifier() == EvqUniform)
881 {
882 outputTriplet(visit, "mul(", ", transpose(", "))");
883 }
884 else
885 {
886 outputTriplet(visit, "mul(", ", ", ")");
887 }
888 }
889 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000890 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
891 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break; // FIXME: Prevent name clashes
892 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
893 default: UNREACHABLE();
894 }
895
896 return true;
897}
898
899bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
900{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000901 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000902
903 switch (node->getOp())
904 {
905 case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break;
906 case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
907 case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000908 case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break;
909 case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break;
910 case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break;
911 case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break;
912 case EOpConvIntToBool:
913 case EOpConvFloatToBool:
914 switch (node->getOperand()->getType().getNominalSize())
915 {
916 case 1: outputTriplet(visit, "bool(", NULL, ")"); break;
917 case 2: outputTriplet(visit, "bool2(", NULL, ")"); break;
918 case 3: outputTriplet(visit, "bool3(", NULL, ")"); break;
919 case 4: outputTriplet(visit, "bool4(", NULL, ")"); break;
920 default: UNREACHABLE();
921 }
922 break;
923 case EOpConvBoolToFloat:
924 case EOpConvIntToFloat:
925 switch (node->getOperand()->getType().getNominalSize())
926 {
927 case 1: outputTriplet(visit, "float(", NULL, ")"); break;
928 case 2: outputTriplet(visit, "float2(", NULL, ")"); break;
929 case 3: outputTriplet(visit, "float3(", NULL, ")"); break;
930 case 4: outputTriplet(visit, "float4(", NULL, ")"); break;
931 default: UNREACHABLE();
932 }
933 break;
934 case EOpConvFloatToInt:
935 case EOpConvBoolToInt:
936 switch (node->getOperand()->getType().getNominalSize())
937 {
938 case 1: outputTriplet(visit, "int(", NULL, ")"); break;
939 case 2: outputTriplet(visit, "int2(", NULL, ")"); break;
940 case 3: outputTriplet(visit, "int3(", NULL, ")"); break;
941 case 4: outputTriplet(visit, "int4(", NULL, ")"); break;
942 default: UNREACHABLE();
943 }
944 break;
945 case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break;
946 case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break;
947 case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break;
948 case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break;
949 case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break;
950 case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break;
951 case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break;
952 case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break;
953 case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break;
954 case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break;
955 case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break;
956 case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break;
957 case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break;
958 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break;
959 case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break;
960 case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break;
961 case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break;
962 case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break;
963 case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break;
964 case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break;
965 case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break;
daniel@transgaming.com45d03582010-03-11 19:41:29 +0000966// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break;
967// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break;
968// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969 case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break;
970 case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break;
971 default: UNREACHABLE();
972 }
973
974 return true;
975}
976
977bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
978{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000979 EShLanguage language = mContext.language;
980 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982 switch (node->getOp())
983 {
984 case EOpSequence: outputTriplet(visit, NULL, ";\n", ";\n"); break;
985 case EOpDeclaration:
986 if (visit == PreVisit)
987 {
988 TIntermSequence &sequence = node->getSequence();
989 TIntermTyped *variable = sequence[0]->getAsTyped();
990 bool visit = true;
991
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000992 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000994 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000995 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000996 if (variable->getQualifier() == EvqGlobal)
997 {
998 out << "static ";
999 }
1000
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001001 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001002
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001003 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001004 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001005 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001006
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001007 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001009 symbol->traverse(this);
1010
1011 out << arrayString(symbol->getType());
1012 }
1013 else
1014 {
1015 (*sit)->traverse(this);
1016 }
1017
1018 if (visit && this->inVisit)
1019 {
1020 if (*sit != sequence.back())
1021 {
1022 visit = this->visitAggregate(InVisit, node);
1023 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001024 }
1025 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001026
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001027 if (visit && this->postVisit)
1028 {
1029 this->visitAggregate(PostVisit, node);
1030 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001032 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1033 {
1034 const TType &type = variable->getType();
1035 const TTypeList &fields = *type.getStruct();
1036
1037 out << "struct " + type.getTypeName() + "\n"
1038 "{\n";
1039
1040 for (unsigned int i = 0; i < fields.size(); i++)
1041 {
1042 const TType &field = *fields[i].type;
1043
1044 out << " " + typeString(field) + " " + field.getFieldName() + ";\n";
1045 }
1046
1047 out << "};\n";
1048 }
1049 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050 }
1051
1052 return false;
1053 }
1054 else if (visit == InVisit)
1055 {
1056 out << ", ";
1057 }
1058 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001059 case EOpPrototype:
1060 if (visit == PreVisit)
1061 {
1062 out << typeString(node->getType()) << " " << node->getName() << "(";
1063
1064 TIntermSequence &arguments = node->getSequence();
1065
1066 for (unsigned int i = 0; i < arguments.size(); i++)
1067 {
1068 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1069
1070 if (symbol)
1071 {
1072 out << argumentString(symbol);
1073
1074 if (i < arguments.size() - 1)
1075 {
1076 out << ", ";
1077 }
1078 }
1079 else UNREACHABLE();
1080 }
1081
1082 out << ");\n";
1083
1084 return false;
1085 }
1086 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 case EOpComma: UNIMPLEMENTED(); /* FIXME */ out << "Comma\n"; return true;
1088 case EOpFunction:
1089 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001090 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001091
1092 if (visit == PreVisit)
1093 {
1094 if (name == "main")
1095 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001096 name = "gl_main";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001097 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001098
1099 out << typeString(node->getType()) << " " << name << "(";
1100
1101 TIntermSequence &sequence = node->getSequence();
1102 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1103
1104 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001105 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001106 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001107
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001108 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001109 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001110 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001111
1112 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001113 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001114 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001116 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001117 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001119
1120 sequence.erase(sequence.begin());
1121
1122 out << ")\n"
1123 "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001124 }
1125 else if (visit == PostVisit)
1126 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001127 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001128 }
1129 }
1130 break;
1131 case EOpFunctionCall:
1132 {
1133 if (visit == PreVisit)
1134 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001135 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001136
1137 if (node->isUserDefined())
1138 {
1139 out << name << "(";
1140 }
1141 else
1142 {
1143 if (name == "texture2D")
1144 {
1145 if (node->getSequence().size() == 2)
1146 {
1147 out << "gl_texture2D(";
1148 }
1149 else if (node->getSequence().size() == 3)
1150 {
1151 out << "gl_texture2DBias(";
1152 }
1153 else UNREACHABLE();
1154 }
1155 else if (name == "texture2DProj")
1156 {
1157 out << "gl_texture2DProj(";
1158 }
1159 else if (name == "texture2DLod")
1160 {
1161 out << "gl_texture2DLod(";
1162 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1163 }
1164 else if (name == "texture2DProjLod")
1165 {
1166 out << "gl_texture2DProjLod(";
1167 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1168 }
1169 else if (name == "textureCube")
1170 {
1171 out << "gl_textureCube("; // FIXME: Incorrect sampling location
1172 }
1173 else
1174 {
1175 UNIMPLEMENTED(); // FIXME
1176 }
1177 }
1178 }
1179 else if (visit == InVisit)
1180 {
1181 out << ", ";
1182 }
1183 else
1184 {
1185 out << ")";
1186 }
1187 }
1188 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001189 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1190 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1191 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1192 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1193 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001194 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1195 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1196 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1197 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1198 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1199 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1200 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1201 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001202 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1203 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1204 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1205 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1206 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1207 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1208 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1209 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1210 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1211 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
1212 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break; // FIXME: Prevent name clashes
1213 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001214 case EOpAtan:
1215 if (node->getSequence().size() == 1)
1216 {
1217 outputTriplet(visit, "atan(", ", ", ")");
1218 }
1219 else if (node->getSequence().size() == 2)
1220 {
1221 outputTriplet(visit, "atan2(", ", ", ")");
1222 }
1223 else UNREACHABLE();
1224 break;
1225 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1226 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1227 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1228 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1229 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1230 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1231 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1232 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1233 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com680553b2010-03-08 21:30:52 +00001234 case EOpFaceForward: outputTriplet(visit, "faceforward(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001235 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1236 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1237 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238 default: UNREACHABLE();
1239 }
1240
1241 return true;
1242}
1243
1244bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1245{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001246 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001247
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001248 if (node->usesTernaryOperator())
1249 {
1250 out << "(";
1251 node->getCondition()->traverse(this);
1252 out << ") ? (";
1253 node->getTrueBlock()->traverse(this);
1254 out << ") : (";
1255 node->getFalseBlock()->traverse(this);
1256 out << ")\n";
1257 }
1258 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259 {
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001260 out << "if(";
1261
1262 node->getCondition()->traverse(this);
1263
1264 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001265 "{\n";
1266
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001267 node->getTrueBlock()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001268
1269 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001270
1271 if (node->getFalseBlock())
1272 {
1273 out << "else\n"
1274 "{\n";
1275
1276 node->getFalseBlock()->traverse(this);
1277
1278 out << ";}\n";
1279 }
1280 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001281
1282 return false;
1283}
1284
1285void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1286{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001287 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001288
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001289 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001290
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001291 if (type.isField())
1292 {
1293 out << type.getFieldName();
1294 }
1295 else
1296 {
1297 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001298
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001299 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001300 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001301 out << "{";
1302 }
1303 else
1304 {
1305 bool matrix = type.isMatrix();
1306 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1307
1308 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001309 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001310 case EbtBool:
1311 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001312 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001313 switch (size)
1314 {
1315 case 1: out << "bool("; break;
1316 case 2: out << "bool2("; break;
1317 case 3: out << "bool3("; break;
1318 case 4: out << "bool4("; break;
1319 default: UNREACHABLE();
1320 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001321 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001322 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001323 break;
1324 case EbtFloat:
1325 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001326 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001327 switch (size)
1328 {
1329 case 1: out << "float("; break;
1330 case 2: out << "float2("; break;
1331 case 3: out << "float3("; break;
1332 case 4: out << "float4("; break;
1333 default: UNREACHABLE();
1334 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001335 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001336 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001337 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001338 switch (size)
1339 {
1340 case 4: out << "float2x2("; break;
1341 case 9: out << "float3x3("; break;
1342 case 16: out << "float4x4("; break;
1343 default: UNREACHABLE();
1344 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001345 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001346 break;
1347 case EbtInt:
1348 if (!matrix)
1349 {
1350 switch (size)
1351 {
1352 case 1: out << "int("; break;
1353 case 2: out << "int2("; break;
1354 case 3: out << "int3("; break;
1355 case 4: out << "int4("; break;
1356 default: UNREACHABLE();
1357 }
1358 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001359 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001360 break;
1361 default:
1362 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001363 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001364 }
1365
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001366 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001367 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001368 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001369 {
1370 case EbtBool:
1371 if (node->getUnionArrayPointer()[i].getBConst())
1372 {
1373 out << "true";
1374 }
1375 else
1376 {
1377 out << "false";
1378 }
1379 break;
1380 case EbtFloat:
1381 out << node->getUnionArrayPointer()[i].getFConst();
1382 break;
1383 case EbtInt:
1384 out << node->getUnionArrayPointer()[i].getIConst();
1385 break;
1386 default:
1387 UNIMPLEMENTED(); // FIXME
1388 }
1389
1390 if (i != size - 1)
1391 {
1392 out << ", ";
1393 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001394 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001395
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001396 if (type.getBasicType() == EbtStruct)
1397 {
1398 out << "}";
1399 }
1400 else
1401 {
1402 out << ")";
1403 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001404 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001405}
1406
1407bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1408{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001409 if (handleExcessiveLoop(node))
1410 {
1411 return false;
1412 }
1413
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001414 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001415
1416 if (!node->testFirst())
1417 {
1418 out << "do\n"
1419 "{\n";
1420 }
1421 else
1422 {
1423 out << "for(";
1424
1425 if (node->getInit())
1426 {
1427 node->getInit()->traverse(this);
1428 }
1429
1430 out << "; ";
1431
1432 if (node->getTest())
1433 {
1434 node->getTest()->traverse(this);
1435 }
1436
1437 out << "; ";
1438
1439 if (node->getTerminal())
1440 {
1441 node->getTerminal()->traverse(this);
1442 }
1443
1444 out << ")\n"
1445 "{\n";
1446 }
1447
1448 if (node->getBody())
1449 {
1450 node->getBody()->traverse(this);
1451 }
1452
1453 out << "}\n";
1454
1455 if (!node->testFirst())
1456 {
1457 out << "while(\n";
1458
1459 node->getTest()->traverse(this);
1460
1461 out << ")";
1462 }
1463
1464 out << ";\n";
1465
1466 return false;
1467}
1468
1469bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1470{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001471 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001472
1473 switch (node->getFlowOp())
1474 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001475 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1476 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1477 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001478 case EOpReturn:
1479 if (visit == PreVisit)
1480 {
1481 if (node->getExpression())
1482 {
1483 out << "return ";
1484 }
1485 else
1486 {
1487 out << "return;\n";
1488 }
1489 }
1490 else if (visit == PostVisit)
1491 {
1492 out << ";\n";
1493 }
1494 break;
1495 default: UNREACHABLE();
1496 }
1497
1498 return true;
1499}
1500
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001501// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1502bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1503{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001504 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001505
1506 // Parse loops of the form:
1507 // for(int index = initial; index [comparator] limit; index += increment)
1508 TIntermSymbol *index = NULL;
1509 TOperator comparator = EOpNull;
1510 int initial = 0;
1511 int limit = 0;
1512 int increment = 0;
1513
1514 // Parse index name and intial value
1515 if (node->getInit())
1516 {
1517 TIntermAggregate *init = node->getInit()->getAsAggregate();
1518
1519 if (init)
1520 {
1521 TIntermSequence &sequence = init->getSequence();
1522 TIntermTyped *variable = sequence[0]->getAsTyped();
1523
1524 if (variable && variable->getQualifier() == EvqTemporary)
1525 {
1526 TIntermBinary *assign = variable->getAsBinaryNode();
1527
1528 if (assign->getOp() == EOpInitialize)
1529 {
1530 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1531 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1532
1533 if (symbol && constant)
1534 {
1535 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1536 {
1537 index = symbol;
1538 initial = constant->getUnionArrayPointer()[0].getIConst();
1539 }
1540 }
1541 }
1542 }
1543 }
1544 }
1545
1546 // Parse comparator and limit value
1547 if (index != NULL && node->getTest())
1548 {
1549 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1550
1551 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1552 {
1553 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1554
1555 if (constant)
1556 {
1557 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1558 {
1559 comparator = test->getOp();
1560 limit = constant->getUnionArrayPointer()[0].getIConst();
1561 }
1562 }
1563 }
1564 }
1565
1566 // Parse increment
1567 if (index != NULL && comparator != EOpNull && node->getTerminal())
1568 {
1569 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1570 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1571
1572 if (binaryTerminal)
1573 {
1574 TOperator op = binaryTerminal->getOp();
1575 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1576
1577 if (constant)
1578 {
1579 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1580 {
1581 int value = constant->getUnionArrayPointer()[0].getIConst();
1582
1583 switch (op)
1584 {
1585 case EOpAddAssign: increment = value; break;
1586 case EOpSubAssign: increment = -value; break;
1587 default: UNIMPLEMENTED();
1588 }
1589 }
1590 }
1591 }
1592 else if (unaryTerminal)
1593 {
1594 TOperator op = unaryTerminal->getOp();
1595
1596 switch (op)
1597 {
1598 case EOpPostIncrement: increment = 1; break;
1599 case EOpPostDecrement: increment = -1; break;
1600 case EOpPreIncrement: increment = 1; break;
1601 case EOpPreDecrement: increment = -1; break;
1602 default: UNIMPLEMENTED();
1603 }
1604 }
1605 }
1606
1607 if (index != NULL && comparator != EOpNull && increment != 0)
1608 {
1609 if (comparator == EOpLessThanEqual)
1610 {
1611 comparator = EOpLessThan;
1612 limit += 1;
1613 }
1614
1615 if (comparator == EOpLessThan)
1616 {
1617 int iterations = (limit - initial + 1) / increment;
1618
1619 if (iterations <= 255)
1620 {
1621 return false; // Not an excessive loop
1622 }
1623
1624 while (iterations > 0)
1625 {
1626 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001627 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001628
1629 // for(int index = initial; index < clampedLimit; index += increment)
1630
1631 out << "for(int ";
1632 index->traverse(this);
1633 out << " = ";
1634 out << initial;
1635
1636 out << "; ";
1637 index->traverse(this);
1638 out << " < ";
1639 out << clampedLimit;
1640
1641 out << "; ";
1642 index->traverse(this);
1643 out << " += ";
1644 out << increment;
1645 out << ")\n"
1646 "{\n";
1647
1648 if (node->getBody())
1649 {
1650 node->getBody()->traverse(this);
1651 }
1652
1653 out << "}\n";
1654
1655 initial += 255 * increment;
1656 iterations -= 255;
1657 }
1658
1659 return true;
1660 }
1661 else UNIMPLEMENTED();
1662 }
1663
1664 return false; // Not handled as an excessive loop
1665}
1666
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1668{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001669 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001670
1671 if (visit == PreVisit && preString)
1672 {
1673 out << preString;
1674 }
1675 else if (visit == InVisit && inString)
1676 {
1677 out << inString;
1678 }
1679 else if (visit == PostVisit && postString)
1680 {
1681 out << postString;
1682 }
1683}
1684
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001685TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1686{
1687 TQualifier qualifier = symbol->getQualifier();
1688 const TType &type = symbol->getType();
1689 const TString &name = symbol->getSymbol();
1690
1691 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
1692}
1693
1694TString OutputHLSL::qualifierString(TQualifier qualifier)
1695{
1696 switch(qualifier)
1697 {
1698 case EvqIn: return "in";
1699 case EvqOut: return "out";
1700 case EvqInOut: return "inout";
1701 case EvqConstReadOnly: return "const";
1702 default: UNREACHABLE();
1703 }
1704
1705 return "";
1706}
1707
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001708TString OutputHLSL::typeString(const TType &type)
1709{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001710 if (type.getBasicType() == EbtStruct)
1711 {
1712 return type.getTypeName();
1713 }
1714 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001715 {
1716 switch (type.getNominalSize())
1717 {
1718 case 2: return "float2x2";
1719 case 3: return "float3x3";
1720 case 4: return "float4x4";
1721 }
1722 }
1723 else
1724 {
1725 switch (type.getBasicType())
1726 {
1727 case EbtFloat:
1728 switch (type.getNominalSize())
1729 {
1730 case 1: return "float";
1731 case 2: return "float2";
1732 case 3: return "float3";
1733 case 4: return "float4";
1734 }
1735 case EbtInt:
1736 switch (type.getNominalSize())
1737 {
1738 case 1: return "int";
1739 case 2: return "int2";
1740 case 3: return "int3";
1741 case 4: return "int4";
1742 }
1743 case EbtBool:
1744 switch (type.getNominalSize())
1745 {
1746 case 1: return "bool";
1747 case 2: return "bool2";
1748 case 3: return "bool3";
1749 case 4: return "bool4";
1750 }
1751 case EbtVoid:
1752 return "void";
1753 case EbtSampler2D:
1754 return "sampler2D";
1755 case EbtSamplerCube:
1756 return "samplerCUBE";
1757 }
1758 }
1759
1760 UNIMPLEMENTED(); // FIXME
1761 return "<unknown type>";
1762}
1763
1764TString OutputHLSL::arrayString(const TType &type)
1765{
1766 if (!type.isArray())
1767 {
1768 return "";
1769 }
1770
1771 char buffer[100];
1772 sprintf(buffer, "[%d]", type.getArraySize());
1773
1774 return buffer;
1775}
1776
1777TString OutputHLSL::initializer(const TType &type)
1778{
1779 TString string;
1780
1781 int arraySize = type.isArray() ? type.getArraySize() : 1;
1782
1783 if (type.isArray())
1784 {
1785 string += "{";
1786 }
1787
1788 for (int element = 0; element < arraySize; element++)
1789 {
1790 string += typeString(type) + "(";
1791
1792 for (int component = 0; component < type.getNominalSize(); component++)
1793 {
1794 string += "0";
1795
1796 if (component < type.getNominalSize() - 1)
1797 {
1798 string += ", ";
1799 }
1800 }
1801
1802 string += ")";
1803
1804 if (element < arraySize - 1)
1805 {
1806 string += ", ";
1807 }
1808 }
1809
1810 if (type.isArray())
1811 {
1812 string += "}";
1813 }
1814
1815 return string;
1816}
1817}