blob: db64eacc01b85da9656e639573ec3f8612ccd357 [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:
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 {
825 outputTriplet(visit, "__equal(", ", ", ")");
826 }
827 else
828 {
829 outputTriplet(visit, "!__equal(", ", ", ")");
830 }
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;
843 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break; // FIXME: Prevent name clashes
844 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
989 out << "struct " + type.getTypeName() + "\n"
990 "{\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 {
1014 out << typeString(node->getType()) << " " << node->getName() << "(";
1015
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.com4f39fd92010-03-08 20:26:45 +00001039 case EOpComma: UNIMPLEMENTED(); /* FIXME */ out << "Comma\n"; return true;
1040 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 {
1046 if (name == "main")
1047 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001048 name = "gl_main";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001050
1051 out << typeString(node->getType()) << " " << name << "(";
1052
1053 TIntermSequence &sequence = node->getSequence();
1054 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1055
1056 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001057 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001058 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001059
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001060 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001062 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001063
1064 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001066 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001069 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001071
1072 sequence.erase(sequence.begin());
1073
1074 out << ")\n"
1075 "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001076 }
1077 else if (visit == PostVisit)
1078 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001079 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080 }
1081 }
1082 break;
1083 case EOpFunctionCall:
1084 {
1085 if (visit == PreVisit)
1086 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001087 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088
1089 if (node->isUserDefined())
1090 {
1091 out << name << "(";
1092 }
1093 else
1094 {
1095 if (name == "texture2D")
1096 {
1097 if (node->getSequence().size() == 2)
1098 {
1099 out << "gl_texture2D(";
1100 }
1101 else if (node->getSequence().size() == 3)
1102 {
1103 out << "gl_texture2DBias(";
1104 }
1105 else UNREACHABLE();
1106 }
1107 else if (name == "texture2DProj")
1108 {
1109 out << "gl_texture2DProj(";
1110 }
1111 else if (name == "texture2DLod")
1112 {
1113 out << "gl_texture2DLod(";
1114 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1115 }
1116 else if (name == "texture2DProjLod")
1117 {
1118 out << "gl_texture2DProjLod(";
1119 UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component
1120 }
1121 else if (name == "textureCube")
1122 {
1123 out << "gl_textureCube("; // FIXME: Incorrect sampling location
1124 }
1125 else
1126 {
1127 UNIMPLEMENTED(); // FIXME
1128 }
1129 }
1130 }
1131 else if (visit == InVisit)
1132 {
1133 out << ", ";
1134 }
1135 else
1136 {
1137 out << ")";
1138 }
1139 }
1140 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001141 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1142 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1143 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1144 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1145 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1147 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1148 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1149 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1150 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1151 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1152 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1153 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001154 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1155 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1156 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1157 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1158 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1159 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1160 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1161 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1162 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1163 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
1164 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break; // FIXME: Prevent name clashes
1165 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001166 case EOpAtan:
1167 if (node->getSequence().size() == 1)
1168 {
1169 outputTriplet(visit, "atan(", ", ", ")");
1170 }
1171 else if (node->getSequence().size() == 2)
1172 {
1173 outputTriplet(visit, "atan2(", ", ", ")");
1174 }
1175 else UNREACHABLE();
1176 break;
1177 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1178 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1179 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1180 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1181 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1182 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1183 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1184 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1185 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com680553b2010-03-08 21:30:52 +00001186 case EOpFaceForward: outputTriplet(visit, "faceforward(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001187 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1188 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1189 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190 default: UNREACHABLE();
1191 }
1192
1193 return true;
1194}
1195
1196bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1197{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001198 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001200 if (node->usesTernaryOperator())
1201 {
1202 out << "(";
1203 node->getCondition()->traverse(this);
1204 out << ") ? (";
1205 node->getTrueBlock()->traverse(this);
1206 out << ") : (";
1207 node->getFalseBlock()->traverse(this);
1208 out << ")\n";
1209 }
1210 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211 {
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001212 out << "if(";
1213
1214 node->getCondition()->traverse(this);
1215
1216 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001217 "{\n";
1218
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001219 node->getTrueBlock()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001220
1221 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001222
1223 if (node->getFalseBlock())
1224 {
1225 out << "else\n"
1226 "{\n";
1227
1228 node->getFalseBlock()->traverse(this);
1229
1230 out << ";}\n";
1231 }
1232 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001233
1234 return false;
1235}
1236
1237void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1238{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001239 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001240
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001241 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001242
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001243 if (type.isField())
1244 {
1245 out << type.getFieldName();
1246 }
1247 else
1248 {
1249 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001250
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001251 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001252 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001253 out << "{";
1254 }
1255 else
1256 {
1257 bool matrix = type.isMatrix();
1258 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1259
1260 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001262 case EbtBool:
1263 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001264 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001265 switch (size)
1266 {
1267 case 1: out << "bool("; break;
1268 case 2: out << "bool2("; break;
1269 case 3: out << "bool3("; break;
1270 case 4: out << "bool4("; break;
1271 default: UNREACHABLE();
1272 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001273 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001274 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001275 break;
1276 case EbtFloat:
1277 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001278 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001279 switch (size)
1280 {
1281 case 1: out << "float("; break;
1282 case 2: out << "float2("; break;
1283 case 3: out << "float3("; break;
1284 case 4: out << "float4("; break;
1285 default: UNREACHABLE();
1286 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001287 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001288 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001289 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001290 switch (size)
1291 {
1292 case 4: out << "float2x2("; break;
1293 case 9: out << "float3x3("; break;
1294 case 16: out << "float4x4("; break;
1295 default: UNREACHABLE();
1296 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001297 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001298 break;
1299 case EbtInt:
1300 if (!matrix)
1301 {
1302 switch (size)
1303 {
1304 case 1: out << "int("; break;
1305 case 2: out << "int2("; break;
1306 case 3: out << "int3("; break;
1307 case 4: out << "int4("; break;
1308 default: UNREACHABLE();
1309 }
1310 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001311 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001312 break;
1313 default:
1314 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001315 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 }
1317
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001318 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001319 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001320 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001321 {
1322 case EbtBool:
1323 if (node->getUnionArrayPointer()[i].getBConst())
1324 {
1325 out << "true";
1326 }
1327 else
1328 {
1329 out << "false";
1330 }
1331 break;
1332 case EbtFloat:
1333 out << node->getUnionArrayPointer()[i].getFConst();
1334 break;
1335 case EbtInt:
1336 out << node->getUnionArrayPointer()[i].getIConst();
1337 break;
1338 default:
1339 UNIMPLEMENTED(); // FIXME
1340 }
1341
1342 if (i != size - 1)
1343 {
1344 out << ", ";
1345 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001346 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001347
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001348 if (type.getBasicType() == EbtStruct)
1349 {
1350 out << "}";
1351 }
1352 else
1353 {
1354 out << ")";
1355 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001356 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001357}
1358
1359bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1360{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001361 if (handleExcessiveLoop(node))
1362 {
1363 return false;
1364 }
1365
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001366 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001367
1368 if (!node->testFirst())
1369 {
1370 out << "do\n"
1371 "{\n";
1372 }
1373 else
1374 {
1375 out << "for(";
1376
1377 if (node->getInit())
1378 {
1379 node->getInit()->traverse(this);
1380 }
1381
1382 out << "; ";
1383
1384 if (node->getTest())
1385 {
1386 node->getTest()->traverse(this);
1387 }
1388
1389 out << "; ";
1390
1391 if (node->getTerminal())
1392 {
1393 node->getTerminal()->traverse(this);
1394 }
1395
1396 out << ")\n"
1397 "{\n";
1398 }
1399
1400 if (node->getBody())
1401 {
1402 node->getBody()->traverse(this);
1403 }
1404
1405 out << "}\n";
1406
1407 if (!node->testFirst())
1408 {
1409 out << "while(\n";
1410
1411 node->getTest()->traverse(this);
1412
1413 out << ")";
1414 }
1415
1416 out << ";\n";
1417
1418 return false;
1419}
1420
1421bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1422{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001423 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001424
1425 switch (node->getFlowOp())
1426 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001427 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1428 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1429 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001430 case EOpReturn:
1431 if (visit == PreVisit)
1432 {
1433 if (node->getExpression())
1434 {
1435 out << "return ";
1436 }
1437 else
1438 {
1439 out << "return;\n";
1440 }
1441 }
1442 else if (visit == PostVisit)
1443 {
1444 out << ";\n";
1445 }
1446 break;
1447 default: UNREACHABLE();
1448 }
1449
1450 return true;
1451}
1452
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001453// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1454bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1455{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001456 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001457
1458 // Parse loops of the form:
1459 // for(int index = initial; index [comparator] limit; index += increment)
1460 TIntermSymbol *index = NULL;
1461 TOperator comparator = EOpNull;
1462 int initial = 0;
1463 int limit = 0;
1464 int increment = 0;
1465
1466 // Parse index name and intial value
1467 if (node->getInit())
1468 {
1469 TIntermAggregate *init = node->getInit()->getAsAggregate();
1470
1471 if (init)
1472 {
1473 TIntermSequence &sequence = init->getSequence();
1474 TIntermTyped *variable = sequence[0]->getAsTyped();
1475
1476 if (variable && variable->getQualifier() == EvqTemporary)
1477 {
1478 TIntermBinary *assign = variable->getAsBinaryNode();
1479
1480 if (assign->getOp() == EOpInitialize)
1481 {
1482 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1483 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1484
1485 if (symbol && constant)
1486 {
1487 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1488 {
1489 index = symbol;
1490 initial = constant->getUnionArrayPointer()[0].getIConst();
1491 }
1492 }
1493 }
1494 }
1495 }
1496 }
1497
1498 // Parse comparator and limit value
1499 if (index != NULL && node->getTest())
1500 {
1501 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1502
1503 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1504 {
1505 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1506
1507 if (constant)
1508 {
1509 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1510 {
1511 comparator = test->getOp();
1512 limit = constant->getUnionArrayPointer()[0].getIConst();
1513 }
1514 }
1515 }
1516 }
1517
1518 // Parse increment
1519 if (index != NULL && comparator != EOpNull && node->getTerminal())
1520 {
1521 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1522 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1523
1524 if (binaryTerminal)
1525 {
1526 TOperator op = binaryTerminal->getOp();
1527 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1528
1529 if (constant)
1530 {
1531 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1532 {
1533 int value = constant->getUnionArrayPointer()[0].getIConst();
1534
1535 switch (op)
1536 {
1537 case EOpAddAssign: increment = value; break;
1538 case EOpSubAssign: increment = -value; break;
1539 default: UNIMPLEMENTED();
1540 }
1541 }
1542 }
1543 }
1544 else if (unaryTerminal)
1545 {
1546 TOperator op = unaryTerminal->getOp();
1547
1548 switch (op)
1549 {
1550 case EOpPostIncrement: increment = 1; break;
1551 case EOpPostDecrement: increment = -1; break;
1552 case EOpPreIncrement: increment = 1; break;
1553 case EOpPreDecrement: increment = -1; break;
1554 default: UNIMPLEMENTED();
1555 }
1556 }
1557 }
1558
1559 if (index != NULL && comparator != EOpNull && increment != 0)
1560 {
1561 if (comparator == EOpLessThanEqual)
1562 {
1563 comparator = EOpLessThan;
1564 limit += 1;
1565 }
1566
1567 if (comparator == EOpLessThan)
1568 {
1569 int iterations = (limit - initial + 1) / increment;
1570
1571 if (iterations <= 255)
1572 {
1573 return false; // Not an excessive loop
1574 }
1575
1576 while (iterations > 0)
1577 {
1578 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001579 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001580
1581 // for(int index = initial; index < clampedLimit; index += increment)
1582
1583 out << "for(int ";
1584 index->traverse(this);
1585 out << " = ";
1586 out << initial;
1587
1588 out << "; ";
1589 index->traverse(this);
1590 out << " < ";
1591 out << clampedLimit;
1592
1593 out << "; ";
1594 index->traverse(this);
1595 out << " += ";
1596 out << increment;
1597 out << ")\n"
1598 "{\n";
1599
1600 if (node->getBody())
1601 {
1602 node->getBody()->traverse(this);
1603 }
1604
1605 out << "}\n";
1606
1607 initial += 255 * increment;
1608 iterations -= 255;
1609 }
1610
1611 return true;
1612 }
1613 else UNIMPLEMENTED();
1614 }
1615
1616 return false; // Not handled as an excessive loop
1617}
1618
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1620{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001621 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001622
1623 if (visit == PreVisit && preString)
1624 {
1625 out << preString;
1626 }
1627 else if (visit == InVisit && inString)
1628 {
1629 out << inString;
1630 }
1631 else if (visit == PostVisit && postString)
1632 {
1633 out << postString;
1634 }
1635}
1636
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001637TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1638{
1639 TQualifier qualifier = symbol->getQualifier();
1640 const TType &type = symbol->getType();
1641 const TString &name = symbol->getSymbol();
1642
1643 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
1644}
1645
1646TString OutputHLSL::qualifierString(TQualifier qualifier)
1647{
1648 switch(qualifier)
1649 {
1650 case EvqIn: return "in";
1651 case EvqOut: return "out";
1652 case EvqInOut: return "inout";
1653 case EvqConstReadOnly: return "const";
1654 default: UNREACHABLE();
1655 }
1656
1657 return "";
1658}
1659
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001660TString OutputHLSL::typeString(const TType &type)
1661{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001662 if (type.getBasicType() == EbtStruct)
1663 {
1664 return type.getTypeName();
1665 }
1666 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667 {
1668 switch (type.getNominalSize())
1669 {
1670 case 2: return "float2x2";
1671 case 3: return "float3x3";
1672 case 4: return "float4x4";
1673 }
1674 }
1675 else
1676 {
1677 switch (type.getBasicType())
1678 {
1679 case EbtFloat:
1680 switch (type.getNominalSize())
1681 {
1682 case 1: return "float";
1683 case 2: return "float2";
1684 case 3: return "float3";
1685 case 4: return "float4";
1686 }
1687 case EbtInt:
1688 switch (type.getNominalSize())
1689 {
1690 case 1: return "int";
1691 case 2: return "int2";
1692 case 3: return "int3";
1693 case 4: return "int4";
1694 }
1695 case EbtBool:
1696 switch (type.getNominalSize())
1697 {
1698 case 1: return "bool";
1699 case 2: return "bool2";
1700 case 3: return "bool3";
1701 case 4: return "bool4";
1702 }
1703 case EbtVoid:
1704 return "void";
1705 case EbtSampler2D:
1706 return "sampler2D";
1707 case EbtSamplerCube:
1708 return "samplerCUBE";
1709 }
1710 }
1711
1712 UNIMPLEMENTED(); // FIXME
1713 return "<unknown type>";
1714}
1715
1716TString OutputHLSL::arrayString(const TType &type)
1717{
1718 if (!type.isArray())
1719 {
1720 return "";
1721 }
1722
1723 char buffer[100];
1724 sprintf(buffer, "[%d]", type.getArraySize());
1725
1726 return buffer;
1727}
1728
1729TString OutputHLSL::initializer(const TType &type)
1730{
1731 TString string;
1732
1733 int arraySize = type.isArray() ? type.getArraySize() : 1;
1734
1735 if (type.isArray())
1736 {
1737 string += "{";
1738 }
1739
1740 for (int element = 0; element < arraySize; element++)
1741 {
1742 string += typeString(type) + "(";
1743
1744 for (int component = 0; component < type.getNominalSize(); component++)
1745 {
1746 string += "0";
1747
1748 if (component < type.getNominalSize() - 1)
1749 {
1750 string += ", ";
1751 }
1752 }
1753
1754 string += ")";
1755
1756 if (element < arraySize - 1)
1757 {
1758 string += ", ";
1759 }
1760 }
1761
1762 if (type.isArray())
1763 {
1764 string += "}";
1765 }
1766
1767 return string;
1768}
1769}