blob: 05da22a442bc4f42b9bf9e06e747c77aeb082475 [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
daniel@transgaming.comb5875982010-04-15 20:44:53 +00009#include "UnfoldSelect.h"
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000010#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011#include "InfoSink.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
13namespace sh
14{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000015// Integer to TString conversion
16TString str(int i)
17{
18 char buffer[20];
19 sprintf(buffer, "%d", i);
20 return buffer;
21}
22
daniel@transgaming.com950f9932010-04-13 03:26:14 +000023OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000025 mUnfoldSelect = new UnfoldSelect(context, this);
26
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000027 mUsesTexture2D = false;
28 mUsesTexture2D_bias = false;
29 mUsesTexture2DProj = false;
30 mUsesTexture2DProj_bias = false;
31 mUsesTextureCube = false;
32 mUsesTextureCube_bias = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000033 mUsesEqualMat2 = false;
34 mUsesEqualMat3 = false;
35 mUsesEqualMat4 = false;
36 mUsesEqualVec2 = false;
37 mUsesEqualVec3 = false;
38 mUsesEqualVec4 = false;
39 mUsesEqualIVec2 = false;
40 mUsesEqualIVec3 = false;
41 mUsesEqualIVec4 = false;
42 mUsesEqualBVec2 = false;
43 mUsesEqualBVec3 = false;
44 mUsesEqualBVec4 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000045
46 mArgumentIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000047}
48
daniel@transgaming.comb5875982010-04-15 20:44:53 +000049OutputHLSL::~OutputHLSL()
50{
51 delete mUnfoldSelect;
52}
53
daniel@transgaming.com950f9932010-04-13 03:26:14 +000054void OutputHLSL::output()
55{
56 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
57 header();
58 footer();
59
60 mContext.infoSink.obj << mHeader.c_str();
61 mContext.infoSink.obj << mBody.c_str();
62 mContext.infoSink.obj << mFooter.c_str();
63}
64
daniel@transgaming.comb5875982010-04-15 20:44:53 +000065TInfoSinkBase &OutputHLSL::getBodyStream()
66{
67 return mBody;
68}
69
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000070void OutputHLSL::header()
71{
daniel@transgaming.com950f9932010-04-13 03:26:14 +000072 EShLanguage language = mContext.language;
73 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000074
75 if (language == EShLangFragment)
76 {
77 TString uniforms;
78 TString varyingInput;
79 TString varyingGlobals;
80
daniel@transgaming.com950f9932010-04-13 03:26:14 +000081 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000082 int semanticIndex = 0;
83
84 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
85 {
86 const TSymbol *symbol = (*namedSymbol).second;
87 const TString &name = symbol->getName();
88
89 if (symbol->isVariable())
90 {
91 const TVariable *variable = static_cast<const TVariable*>(symbol);
92 const TType &type = variable->getType();
93 TQualifier qualifier = type.getQualifier();
94
95 if (qualifier == EvqUniform)
96 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +000097 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
98 {
99 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101 }
102 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
103 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000104 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
105 {
106 // Program linking depends on this exact format
107 varyingInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
108 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000109
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000110 semanticIndex += type.isArray() ? type.getArraySize() : 1;
111 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000113 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000114 {
115 // Globals are declared and intialized as an aggregate node
116 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000117 else if (qualifier == EvqConst)
118 {
119 // Constants are repeated as literals where used
120 }
121 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122 }
123 }
124
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000125 out << "uniform float4 gl_Window;\n"
126 "uniform float2 gl_Depth;\n"
daniel@transgaming.com5af64272010-04-15 20:45:12 +0000127 "uniform bool gl_PointsOrLines;\n"
128 "uniform bool gl_FrontCCW;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000129 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130 out << uniforms;
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000131 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000132 "struct PS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133 "{\n";
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000134 out << varyingInput;
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000135 out << " float4 gl_FragCoord : TEXCOORD" << semanticIndex << ";\n";
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000136 out << " float vFace : VFACE;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000137 "};\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 "\n";
139 out << varyingGlobals;
140 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000141 "struct PS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142 "{\n"
143 " float4 gl_Color[1] : COLOR;\n"
144 "};\n"
145 "\n"
146 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000147 "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000148 "static float2 gl_PointCoord = float2(0.5, 0.5);\n"
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000149 "static bool gl_FrontFacing = false;\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150 "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000151
152 if (mUsesTexture2D)
153 {
154 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
155 "{\n"
156 " return tex2D(s, t);\n"
157 "}\n"
158 "\n";
159 }
160
161 if (mUsesTexture2D_bias)
162 {
163 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
164 "{\n"
165 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
166 "}\n"
167 "\n";
168 }
169
170 if (mUsesTexture2DProj)
171 {
172 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
173 "{\n"
174 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
175 "}\n"
176 "\n"
177 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
178 "{\n"
179 " return tex2Dproj(s, t);\n"
180 "}\n"
181 "\n";
182 }
183
184 if (mUsesTexture2DProj_bias)
185 {
186 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
187 "{\n"
188 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
189 "}\n"
190 "\n"
191 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
192 "{\n"
193 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
194 "}\n"
195 "\n";
196 }
197
198 if (mUsesTextureCube)
199 {
200 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
201 "{\n"
202 " return texCUBE(s, t);\n"
203 "}\n"
204 "\n";
205 }
206
207 if (mUsesTextureCube_bias)
208 {
209 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
210 "{\n"
211 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
212 "}\n"
213 "\n";
214 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000216 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217 {
218 TString uniforms;
219 TString attributeInput;
220 TString attributeGlobals;
221 TString varyingOutput;
222 TString varyingGlobals;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000224 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225 int semanticIndex = 0;
226
227 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
228 {
229 const TSymbol *symbol = (*namedSymbol).second;
230 const TString &name = symbol->getName();
231
232 if (symbol->isVariable())
233 {
234 const TVariable *variable = static_cast<const TVariable*>(symbol);
235 const TType &type = variable->getType();
236 TQualifier qualifier = type.getQualifier();
237
238 if (qualifier == EvqUniform)
239 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000240 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
241 {
242 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
243 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000244 }
245 else if (qualifier == EvqAttribute)
246 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000247 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
248 {
249 attributeInput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD" + str(semanticIndex) + ";\n";
250 attributeGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000251
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000252 semanticIndex += type.isArray() ? type.getArraySize() : 1;
253 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000254 }
255 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
256 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000257 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
258 {
259 // Program linking depends on this exact format
260 varyingOutput += " " + typeString(type) + " " + decorate(name) + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link
261 varyingGlobals += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
262 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000263 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000264 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000266 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000268 else if (qualifier == EvqConst)
269 {
270 // Constants are repeated as literals where used
271 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272 else UNREACHABLE();
273 }
274 }
275
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000276 out << "uniform float2 gl_HalfPixelSize;\n"
277 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 out << uniforms;
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000279 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000280 "struct VS_INPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281 "{\n";
282 out << attributeInput;
283 out << "};\n"
284 "\n";
285 out << attributeGlobals;
286 out << "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000287 "struct VS_OUTPUT\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288 "{\n"
289 " float4 gl_Position : POSITION;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000290 " float gl_PointSize : PSIZE;\n"
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000291 " float4 gl_FragCoord : TEXCOORD0;\n"; // Actual semantic index assigned during link
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000292 out << varyingOutput;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293 out << "};\n"
294 "\n"
295 "static float4 gl_Position = float4(0, 0, 0, 0);\n"
daniel@transgaming.comccad59f2010-03-26 04:08:39 +0000296 "static float gl_PointSize = float(1);\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297 out << varyingGlobals;
298 out << "\n";
299 }
300
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000301 out << "struct gl_DepthRangeParameters\n"
302 "{\n"
303 " float near;\n"
304 " float far;\n"
305 " float diff;\n"
306 "};\n"
307 "\n"
308 "uniform gl_DepthRangeParameters gl_DepthRange;\n"
309 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000310 "float vec1(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311 "{\n"
312 " return x;\n"
313 "}\n"
314 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000315 "float vec1(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316 "{\n"
317 " return xy[0];\n"
318 "}\n"
319 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000320 "float vec1(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321 "{\n"
322 " return xyz[0];\n"
323 "}\n"
324 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000325 "float vec1(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 "{\n"
327 " return xyzw[0];\n"
328 "}\n"
329 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000330 "float2 vec2(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331 "{\n"
332 " return float2(x, x);\n"
333 "}\n"
334 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000335 "float2 vec2(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 "{\n"
337 " return float2(x, y);\n"
338 "}\n"
339 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000340 "float2 vec2(float2 xy)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341 "{\n"
342 " return xy;\n"
343 "}\n"
344 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000345 "float2 vec2(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 "{\n"
347 " return float2(xyz[0], xyz[1]);\n"
348 "}\n"
349 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000350 "float2 vec2(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 "{\n"
352 " return float2(xyzw[0], xyzw[1]);\n"
353 "}\n"
354 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000355 "float3 vec3(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000356 "{\n"
357 " return float3(x, x, x);\n"
358 "}\n"
359 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000360 "float3 vec3(float x, float y, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361 "{\n"
362 " return float3(x, y, z);\n"
363 "}\n"
364 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000365 "float3 vec3(float2 xy, float z)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366 "{\n"
367 " return float3(xy[0], xy[1], z);\n"
368 "}\n"
369 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000370 "float3 vec3(float x, float2 yz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371 "{\n"
372 " return float3(x, yz[0], yz[1]);\n"
373 "}\n"
374 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000375 "float3 vec3(float3 xyz)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000376 "{\n"
377 " return xyz;\n"
378 "}\n"
379 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000380 "float3 vec3(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381 "{\n"
382 " return float3(xyzw[0], xyzw[1], xyzw[2]);\n"
383 "}\n"
384 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000385 "float4 vec4(float x)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 "{\n"
387 " return float4(x, x, x, x);\n"
388 "}\n"
389 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000390 "float4 vec4(float x, float y, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391 "{\n"
392 " return float4(x, y, z, w);\n"
393 "}\n"
394 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000395 "float4 vec4(float2 xy, float z, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 "{\n"
397 " return float4(xy[0], xy[1], z, w);\n"
398 "}\n"
399 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000400 "float4 vec4(float x, float2 yz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401 "{\n"
402 " return float4(x, yz[0], yz[1], w);\n"
403 "}\n"
404 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000405 "float4 vec4(float x, float y, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000406 "{\n"
407 " return float4(x, y, zw[0], zw[1]);\n"
408 "}\n"
409 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000410 "float4 vec4(float2 xy, float2 zw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 "{\n"
412 " return float4(xy[0], xy[1], zw[0], zw[1]);\n"
413 "}\n"
414 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000415 "float4 vec4(float3 xyz, float w)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416 "{\n"
417 " return float4(xyz[0], xyz[1], xyz[2], w);\n"
418 "}\n"
419 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000420 "float4 vec4(float x, float3 yzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421 "{\n"
422 " return float4(x, yzw[0], yzw[1], yzw[2]);\n"
423 "}\n"
424 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000425 "float4 vec4(float4 xyzw)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426 "{\n"
427 " return xyzw;\n"
428 "}\n"
429 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000430 "bool xor(bool p, bool q)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431 "{\n"
432 " return (p || q) && !(p && q);\n"
433 "}\n"
434 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000435 "float mod(float x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436 "{\n"
437 " return x - y * floor(x / y);\n"
438 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000439 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000440 "float2 mod(float2 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 "{\n"
442 " return x - y * floor(x / y);\n"
443 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000444 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000445 "float3 mod(float3 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446 "{\n"
447 " return x - y * floor(x / y);\n"
448 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000449 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000450 "float4 mod(float4 x, float y)\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451 "{\n"
452 " return x - y * floor(x / y);\n"
453 "}\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000454 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000455 "float faceforward(float N, float I, float Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000456 "{\n"
457 " if(dot(Nref, I) < 0)\n"
458 " {\n"
459 " return N;\n"
460 " }\n"
461 " else\n"
462 " {\n"
463 " return -N;\n"
464 " }\n"
465 "}\n"
466 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000467 "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000468 "{\n"
469 " if(dot(Nref, I) < 0)\n"
470 " {\n"
471 " return N;\n"
472 " }\n"
473 " else\n"
474 " {\n"
475 " return -N;\n"
476 " }\n"
477 "}\n"
478 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000479 "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000480 "{\n"
481 " if(dot(Nref, I) < 0)\n"
482 " {\n"
483 " return N;\n"
484 " }\n"
485 " else\n"
486 " {\n"
487 " return -N;\n"
488 " }\n"
489 "}\n"
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000490 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000491 "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
daniel@transgaming.com680553b2010-03-08 21:30:52 +0000492 "{\n"
493 " if(dot(Nref, I) < 0)\n"
494 " {\n"
495 " return N;\n"
496 " }\n"
497 " else\n"
498 " {\n"
499 " return -N;\n"
500 " }\n"
501 "}\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502 "\n";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000503
504 if (mUsesEqualMat2)
505 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000506 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000507 "{\n"
508 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
509 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
510 "}\n";
511 }
512
513 if (mUsesEqualMat3)
514 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000515 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000516 "{\n"
517 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
518 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
519 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
520 "}\n";
521 }
522
523 if (mUsesEqualMat4)
524 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000525 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000526 "{\n"
527 " 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"
528 " 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"
529 " 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"
530 " 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"
531 "}\n";
532 }
533
534 if (mUsesEqualVec2)
535 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000536 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000537 "{\n"
538 " return v.x == u.x && v.y == u.y;\n"
539 "}\n";
540 }
541
542 if (mUsesEqualVec3)
543 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000544 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000545 "{\n"
546 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
547 "}\n";
548 }
549
550 if (mUsesEqualVec4)
551 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000552 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000553 "{\n"
554 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
555 "}\n";
556 }
557
558 if (mUsesEqualIVec2)
559 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000560 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000561 "{\n"
562 " return v.x == u.x && v.y == u.y;\n"
563 "}\n";
564 }
565
566 if (mUsesEqualIVec3)
567 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000568 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000569 "{\n"
570 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
571 "}\n";
572 }
573
574 if (mUsesEqualIVec4)
575 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000576 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000577 "{\n"
578 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
579 "}\n";
580 }
581
582 if (mUsesEqualBVec2)
583 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000584 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000585 "{\n"
586 " return v.x == u.x && v.y == u.y;\n"
587 "}\n";
588 }
589
590 if (mUsesEqualBVec3)
591 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000592 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000593 "{\n"
594 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
595 "}\n";
596 }
597
598 if (mUsesEqualBVec4)
599 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000600 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000601 "{\n"
602 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
603 "}\n";
604 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000605}
606
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000607void OutputHLSL::footer()
608{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000609 EShLanguage language = mContext.language;
610 TInfoSinkBase &out = mFooter;
611 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000612
613 if (language == EShLangFragment)
614 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000615 out << "PS_OUTPUT main(PS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000616 "{\n"
617 " float rhw = 1.0 / input.gl_FragCoord.w;\n"
618 " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * gl_Window.x + gl_Window.z;\n"
619 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * gl_Window.y + gl_Window.w;\n"
620 " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * gl_Depth.x + gl_Depth.y;\n"
621 " gl_FragCoord.w = rhw;\n"
daniel@transgaming.com5af64272010-04-15 20:45:12 +0000622 " gl_FrontFacing = gl_PointsOrLines || (gl_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000623
624 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
625 {
626 const TSymbol *symbol = (*namedSymbol).second;
627 const TString &name = symbol->getName();
628
629 if (symbol->isVariable())
630 {
631 const TVariable *variable = static_cast<const TVariable*>(symbol);
632 const TType &type = variable->getType();
633 TQualifier qualifier = type.getQualifier();
634
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000635 if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000636 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000637 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
638 {
639 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
640 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000641 }
642 }
643 }
644
645 out << "\n"
646 " gl_main();\n"
647 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000648 " PS_OUTPUT output;\n"
649 " output.gl_Color[0] = gl_Color[0];\n";
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000650 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000651 else // Vertex shader
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000652 {
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000653 out << "VS_OUTPUT main(VS_INPUT input)\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000654 "{\n";
655
656 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
657 {
658 const TSymbol *symbol = (*namedSymbol).second;
659 const TString &name = symbol->getName();
660
661 if (symbol->isVariable())
662 {
663 const TVariable *variable = static_cast<const TVariable*>(symbol);
664 const TType &type = variable->getType();
665 TQualifier qualifier = type.getQualifier();
666
667 if (qualifier == EvqAttribute)
668 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000669 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
670 {
671 out << " " + decorate(name) + " = input." + decorate(name) + ";\n";
672 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000673 }
674 }
675 }
676
677 out << "\n"
678 " gl_main();\n"
679 "\n"
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000680 " VS_OUTPUT output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000681 " output.gl_Position.x = gl_Position.x - gl_HalfPixelSize.x * gl_Position.w;\n"
682 " output.gl_Position.y = -(gl_Position.y - gl_HalfPixelSize.y * gl_Position.w);\n"
683 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
684 " output.gl_Position.w = gl_Position.w;\n"
685 " output.gl_PointSize = gl_PointSize;\n"
686 " output.gl_FragCoord = gl_Position;\n";
687
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000688 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000689
690 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
691 {
692 const TSymbol *symbol = (*namedSymbol).second;
693 const TString &name = symbol->getName();
694
695 if (symbol->isVariable())
696 {
697 const TVariable *variable = static_cast<const TVariable*>(symbol);
698 TQualifier qualifier = variable->getType().getQualifier();
699
700 if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
701 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000702 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
703 {
704 // Program linking depends on this exact format
705 out << " output." + decorate(name) + " = " + decorate(name) + ";\n";
706 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000707 }
708 }
709 }
710 }
711
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000712 out << " return output;\n"
daniel@transgaming.come78c0c92010-03-28 19:36:06 +0000713 "}\n";
714}
715
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716void OutputHLSL::visitSymbol(TIntermSymbol *node)
717{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000718 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000719
720 TString name = node->getSymbol();
721
722 if (name == "gl_FragColor")
723 {
724 out << "gl_Color[0]";
725 }
726 else if (name == "gl_FragData")
727 {
728 out << "gl_Color";
729 }
730 else
731 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000732 TQualifier qualifier = node->getQualifier();
733
734 if (qualifier == EvqUniform)
735 {
736 mReferencedUniforms.insert(name.c_str());
737 }
738 else if (qualifier == EvqAttribute)
739 {
740 mReferencedAttributes.insert(name.c_str());
741 }
742 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
743 {
744 mReferencedVaryings.insert(name.c_str());
745 }
746
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000747 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000748 }
749}
750
751bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
752{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000753 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754
755 switch (node->getOp())
756 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000757 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
758 case EOpInitialize: outputTriplet(visit, NULL, " = ", NULL); break;
759 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
760 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
761 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
762 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
763 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
764 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000765 if (visit == PreVisit)
766 {
767 out << "(";
768 }
769 else if (visit == InVisit)
770 {
771 out << " = mul(";
772 node->getLeft()->traverse(this);
773 out << ", transpose(";
774 }
775 else
776 {
777 out << "))";
778 }
779 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000780 case EOpMatrixTimesMatrixAssign:
781 if (visit == PreVisit)
782 {
783 out << "(";
784 }
785 else if (visit == InVisit)
786 {
787 out << " = mul(";
788 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000789 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000790 }
791 else
792 {
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000793 out << ")";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000794 }
795 break;
796 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
797 case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break;
798 case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break;
799 case EOpIndexDirectStruct: outputTriplet(visit, NULL, ".", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000800 case EOpVectorSwizzle:
801 if (visit == InVisit)
802 {
803 out << ".";
804
805 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
806
807 if (swizzle)
808 {
809 TIntermSequence &sequence = swizzle->getSequence();
810
811 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
812 {
813 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
814
815 if (element)
816 {
817 int i = element->getUnionArrayPointer()[0].getIConst();
818
819 switch (i)
820 {
821 case 0: out << "x"; break;
822 case 1: out << "y"; break;
823 case 2: out << "z"; break;
824 case 3: out << "w"; break;
825 default: UNREACHABLE();
826 }
827 }
828 else UNREACHABLE();
829 }
830 }
831 else UNREACHABLE();
832
833 return false; // Fully processed
834 }
835 break;
836 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
837 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
838 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
839 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000840 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000841 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000842 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000843 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000844 if (node->getOp() == EOpEqual)
845 {
846 outputTriplet(visit, "(", " == ", ")");
847 }
848 else
849 {
850 outputTriplet(visit, "(", " != ", ")");
851 }
852 }
853 else if (node->getLeft()->getBasicType() == EbtStruct)
854 {
855 if (node->getOp() == EOpEqual)
856 {
857 out << "(";
858 }
859 else
860 {
861 out << "!(";
862 }
863
864 const TTypeList *fields = node->getLeft()->getType().getStruct();
865
866 for (size_t i = 0; i < fields->size(); i++)
867 {
868 const TType *fieldType = (*fields)[i].type;
869
870 node->getLeft()->traverse(this);
871 out << "." + fieldType->getFieldName() + " == ";
872 node->getRight()->traverse(this);
873 out << "." + fieldType->getFieldName();
874
875 if (i < fields->size() - 1)
876 {
877 out << " && ";
878 }
879 }
880
881 out << ")";
882
883 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000884 }
885 else
886 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000887 if (node->getLeft()->isMatrix())
888 {
889 switch (node->getLeft()->getSize())
890 {
891 case 2 * 2: mUsesEqualMat2 = true; break;
892 case 3 * 3: mUsesEqualMat3 = true; break;
893 case 4 * 4: mUsesEqualMat4 = true; break;
894 default: UNREACHABLE();
895 }
896 }
897 else if (node->getLeft()->isVector())
898 {
899 switch (node->getLeft()->getBasicType())
900 {
901 case EbtFloat:
902 switch (node->getLeft()->getSize())
903 {
904 case 2: mUsesEqualVec2 = true; break;
905 case 3: mUsesEqualVec3 = true; break;
906 case 4: mUsesEqualVec4 = true; break;
907 default: UNREACHABLE();
908 }
909 break;
910 case EbtInt:
911 switch (node->getLeft()->getSize())
912 {
913 case 2: mUsesEqualIVec2 = true; break;
914 case 3: mUsesEqualIVec3 = true; break;
915 case 4: mUsesEqualIVec4 = true; break;
916 default: UNREACHABLE();
917 }
918 break;
919 case EbtBool:
920 switch (node->getLeft()->getSize())
921 {
922 case 2: mUsesEqualBVec2 = true; break;
923 case 3: mUsesEqualBVec3 = true; break;
924 case 4: mUsesEqualBVec4 = true; break;
925 default: UNREACHABLE();
926 }
927 break;
928 default: UNREACHABLE();
929 }
930 }
931 else UNREACHABLE();
932
933 if (node->getOp() == EOpEqual)
934 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000935 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000936 }
937 else
938 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000939 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000940 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000941 }
942 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000943 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
944 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
945 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
946 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
947 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000948 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000949 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
950 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
951 case EOpMatrixTimesMatrix: outputTriplet(visit, "mul(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000952 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +0000953 case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
955 default: UNREACHABLE();
956 }
957
958 return true;
959}
960
961bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
962{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000963 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964
965 switch (node->getOp())
966 {
967 case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break;
968 case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
969 case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970 case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break;
971 case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break;
972 case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break;
973 case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break;
974 case EOpConvIntToBool:
975 case EOpConvFloatToBool:
976 switch (node->getOperand()->getType().getNominalSize())
977 {
978 case 1: outputTriplet(visit, "bool(", NULL, ")"); break;
979 case 2: outputTriplet(visit, "bool2(", NULL, ")"); break;
980 case 3: outputTriplet(visit, "bool3(", NULL, ")"); break;
981 case 4: outputTriplet(visit, "bool4(", NULL, ")"); break;
982 default: UNREACHABLE();
983 }
984 break;
985 case EOpConvBoolToFloat:
986 case EOpConvIntToFloat:
987 switch (node->getOperand()->getType().getNominalSize())
988 {
989 case 1: outputTriplet(visit, "float(", NULL, ")"); break;
990 case 2: outputTriplet(visit, "float2(", NULL, ")"); break;
991 case 3: outputTriplet(visit, "float3(", NULL, ")"); break;
992 case 4: outputTriplet(visit, "float4(", NULL, ")"); break;
993 default: UNREACHABLE();
994 }
995 break;
996 case EOpConvFloatToInt:
997 case EOpConvBoolToInt:
998 switch (node->getOperand()->getType().getNominalSize())
999 {
1000 case 1: outputTriplet(visit, "int(", NULL, ")"); break;
1001 case 2: outputTriplet(visit, "int2(", NULL, ")"); break;
1002 case 3: outputTriplet(visit, "int3(", NULL, ")"); break;
1003 case 4: outputTriplet(visit, "int4(", NULL, ")"); break;
1004 default: UNREACHABLE();
1005 }
1006 break;
1007 case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break;
1008 case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break;
1009 case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break;
1010 case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break;
1011 case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break;
1012 case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break;
1013 case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break;
1014 case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break;
1015 case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break;
1016 case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break;
1017 case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break;
1018 case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break;
1019 case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break;
1020 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break;
1021 case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break;
1022 case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break;
1023 case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break;
1024 case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break;
1025 case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break;
1026 case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break;
1027 case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break;
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001028// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break;
1029// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break;
1030// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break;
1032 case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break;
1033 default: UNREACHABLE();
1034 }
1035
1036 return true;
1037}
1038
1039bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1040{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001041 EShLanguage language = mContext.language;
1042 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044 switch (node->getOp())
1045 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001046 case EOpSequence:
1047 {
1048 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1049 {
1050 if (isSingleStatement(*sit))
1051 {
1052 mUnfoldSelect->traverse(*sit);
1053 }
1054
1055 (*sit)->traverse(this);
1056
1057 out << ";\n";
1058 }
1059
1060 return false;
1061 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062 case EOpDeclaration:
1063 if (visit == PreVisit)
1064 {
1065 TIntermSequence &sequence = node->getSequence();
1066 TIntermTyped *variable = sequence[0]->getAsTyped();
1067 bool visit = true;
1068
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001069 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001070 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001071 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001073 if (variable->getQualifier() == EvqGlobal)
1074 {
1075 out << "static ";
1076 }
1077
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001078 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001080 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001081 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001082 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001084 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001086 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001087 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001088 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001089 }
1090 else
1091 {
1092 (*sit)->traverse(this);
1093 }
1094
1095 if (visit && this->inVisit)
1096 {
1097 if (*sit != sequence.back())
1098 {
1099 visit = this->visitAggregate(InVisit, node);
1100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101 }
1102 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001103
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001104 if (visit && this->postVisit)
1105 {
1106 this->visitAggregate(PostVisit, node);
1107 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001108 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001109 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1110 {
1111 const TType &type = variable->getType();
1112 const TTypeList &fields = *type.getStruct();
1113
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001114 out << "struct " + decorate(type.getTypeName()) + "\n"
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001115 "{\n";
1116
1117 for (unsigned int i = 0; i < fields.size(); i++)
1118 {
1119 const TType &field = *fields[i].type;
1120
1121 out << " " + typeString(field) + " " + field.getFieldName() + ";\n";
1122 }
1123
1124 out << "};\n";
1125 }
1126 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001127 }
1128
1129 return false;
1130 }
1131 else if (visit == InVisit)
1132 {
1133 out << ", ";
1134 }
1135 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001136 case EOpPrototype:
1137 if (visit == PreVisit)
1138 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001139 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001140
1141 TIntermSequence &arguments = node->getSequence();
1142
1143 for (unsigned int i = 0; i < arguments.size(); i++)
1144 {
1145 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1146
1147 if (symbol)
1148 {
1149 out << argumentString(symbol);
1150
1151 if (i < arguments.size() - 1)
1152 {
1153 out << ", ";
1154 }
1155 }
1156 else UNREACHABLE();
1157 }
1158
1159 out << ");\n";
1160
1161 return false;
1162 }
1163 break;
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001164 case EOpComma: outputTriplet(visit, NULL, ", ", NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001165 case EOpFunction:
1166 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001167 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001168
1169 if (visit == PreVisit)
1170 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001171 out << typeString(node->getType()) << " ";
1172
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001173 if (name == "main")
1174 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001175 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001176 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001177 else
1178 {
1179 out << decorate(name) << "(";
1180 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001181
1182 TIntermSequence &sequence = node->getSequence();
1183 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1184
1185 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001186 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001187 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001188
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001189 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001191 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001192
1193 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001194 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001195 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001196 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001197 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001198 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001200
1201 sequence.erase(sequence.begin());
1202
1203 out << ")\n"
1204 "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205 }
1206 else if (visit == PostVisit)
1207 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001208 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209 }
1210 }
1211 break;
1212 case EOpFunctionCall:
1213 {
1214 if (visit == PreVisit)
1215 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001216 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001217
1218 if (node->isUserDefined())
1219 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001220 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221 }
1222 else
1223 {
1224 if (name == "texture2D")
1225 {
1226 if (node->getSequence().size() == 2)
1227 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001228 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001229 }
1230 else if (node->getSequence().size() == 3)
1231 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001232 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001233 }
1234 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001235
1236 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001237 }
1238 else if (name == "texture2DProj")
1239 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001240 if (node->getSequence().size() == 2)
1241 {
1242 mUsesTexture2DProj = true;
1243 }
1244 else if (node->getSequence().size() == 3)
1245 {
1246 mUsesTexture2DProj_bias = true;
1247 }
1248 else UNREACHABLE();
1249
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250 out << "gl_texture2DProj(";
1251 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001252 else if (name == "textureCube")
1253 {
1254 if (node->getSequence().size() == 2)
1255 {
1256 mUsesTextureCube = true;
1257 }
1258 else if (node->getSequence().size() == 3)
1259 {
1260 mUsesTextureCube_bias = true;
1261 }
1262 else UNREACHABLE();
1263
1264 out << "gl_textureCube(";
1265 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001266 else if (name == "texture2DLod")
1267 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001268 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001269 }
1270 else if (name == "texture2DProjLod")
1271 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001272 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001273 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001274 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001275 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001276 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001278 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001279 }
1280 }
1281 else if (visit == InVisit)
1282 {
1283 out << ", ";
1284 }
1285 else
1286 {
1287 out << ")";
1288 }
1289 }
1290 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001291 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
1292 case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break;
1293 case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break;
1294 case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break;
1295 case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001296 case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break;
1297 case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break;
1298 case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break;
1299 case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break;
1300 case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break;
1301 case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break;
1302 case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break;
1303 case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001304 case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break;
1305 case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break;
1306 case EOpConstructMat4: outputTriplet(visit, "float4x4(", ", ", ")"); break;
1307 case EOpConstructStruct: outputTriplet(visit, "{", ", ", "}"); break;
1308 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1309 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1310 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1311 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1312 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1313 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.com3c010c02010-04-13 19:53:47 +00001314 case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001315 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 case EOpAtan:
1317 if (node->getSequence().size() == 1)
1318 {
1319 outputTriplet(visit, "atan(", ", ", ")");
1320 }
1321 else if (node->getSequence().size() == 2)
1322 {
1323 outputTriplet(visit, "atan2(", ", ", ")");
1324 }
1325 else UNREACHABLE();
1326 break;
1327 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1328 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1329 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1330 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1331 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1332 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1333 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1334 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1335 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com680553b2010-03-08 21:30:52 +00001336 case EOpFaceForward: outputTriplet(visit, "faceforward(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001337 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1338 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1339 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001340 default: UNREACHABLE();
1341 }
1342
1343 return true;
1344}
1345
1346bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1347{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001348 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001349
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001350 if (node->usesTernaryOperator())
1351 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001352 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001353 }
1354 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001356 mUnfoldSelect->traverse(node->getCondition());
1357
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001358 out << "if(";
1359
1360 node->getCondition()->traverse(this);
1361
1362 out << ")\n"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001363 "{\n";
1364
daniel@transgaming.combb885322010-04-15 20:45:24 +00001365 if (node->getTrueBlock())
1366 {
1367 node->getTrueBlock()->traverse(this);
1368 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001369
1370 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001371
1372 if (node->getFalseBlock())
1373 {
1374 out << "else\n"
1375 "{\n";
1376
1377 node->getFalseBlock()->traverse(this);
1378
1379 out << ";}\n";
1380 }
1381 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001382
1383 return false;
1384}
1385
1386void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1387{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001388 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001389
alokp@chromium.orgdd037b22010-03-30 18:47:20 +00001390 const TType &type = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001391
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001392 if (type.isField())
1393 {
1394 out << type.getFieldName();
1395 }
1396 else
1397 {
1398 int size = type.getObjectSize();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001399
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001400 if (type.getBasicType() == EbtStruct)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001401 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001402 out << "{";
1403 }
1404 else
1405 {
1406 bool matrix = type.isMatrix();
1407 TBasicType elementType = node->getUnionArrayPointer()[0].getType();
1408
1409 switch (elementType)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001410 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001411 case EbtBool:
1412 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001413 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001414 switch (size)
1415 {
1416 case 1: out << "bool("; break;
1417 case 2: out << "bool2("; break;
1418 case 3: out << "bool3("; break;
1419 case 4: out << "bool4("; break;
1420 default: UNREACHABLE();
1421 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001422 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001423 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001424 break;
1425 case EbtFloat:
1426 if (!matrix)
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001427 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001428 switch (size)
1429 {
1430 case 1: out << "float("; break;
1431 case 2: out << "float2("; break;
1432 case 3: out << "float3("; break;
1433 case 4: out << "float4("; break;
1434 default: UNREACHABLE();
1435 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001436 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001437 else
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001438 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001439 switch (size)
1440 {
1441 case 4: out << "float2x2("; break;
1442 case 9: out << "float3x3("; break;
1443 case 16: out << "float4x4("; break;
1444 default: UNREACHABLE();
1445 }
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001446 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001447 break;
1448 case EbtInt:
1449 if (!matrix)
1450 {
1451 switch (size)
1452 {
1453 case 1: out << "int("; break;
1454 case 2: out << "int2("; break;
1455 case 3: out << "int3("; break;
1456 case 4: out << "int4("; break;
1457 default: UNREACHABLE();
1458 }
1459 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001460 else UNREACHABLE();
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001461 break;
1462 default:
1463 UNIMPLEMENTED(); // FIXME
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001464 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001465 }
1466
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001467 for (int i = 0; i < size; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001468 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001469 switch (node->getUnionArrayPointer()[i].getType())
daniel@transgaming.com45d03582010-03-11 19:41:29 +00001470 {
1471 case EbtBool:
1472 if (node->getUnionArrayPointer()[i].getBConst())
1473 {
1474 out << "true";
1475 }
1476 else
1477 {
1478 out << "false";
1479 }
1480 break;
1481 case EbtFloat:
1482 out << node->getUnionArrayPointer()[i].getFConst();
1483 break;
1484 case EbtInt:
1485 out << node->getUnionArrayPointer()[i].getIConst();
1486 break;
1487 default:
1488 UNIMPLEMENTED(); // FIXME
1489 }
1490
1491 if (i != size - 1)
1492 {
1493 out << ", ";
1494 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001496
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001497 if (type.getBasicType() == EbtStruct)
1498 {
1499 out << "}";
1500 }
1501 else
1502 {
1503 out << ")";
1504 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001505 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001506}
1507
1508bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1509{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001510 if (handleExcessiveLoop(node))
1511 {
1512 return false;
1513 }
1514
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001515 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001516
1517 if (!node->testFirst())
1518 {
1519 out << "do\n"
1520 "{\n";
1521 }
1522 else
1523 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001524 if (node->getInit())
1525 {
1526 mUnfoldSelect->traverse(node->getInit());
1527 }
1528
1529 if (node->getTest())
1530 {
1531 mUnfoldSelect->traverse(node->getTest());
1532 }
1533
1534 if (node->getTerminal())
1535 {
1536 mUnfoldSelect->traverse(node->getTerminal());
1537 }
1538
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001539 out << "for(";
1540
1541 if (node->getInit())
1542 {
1543 node->getInit()->traverse(this);
1544 }
1545
1546 out << "; ";
1547
1548 if (node->getTest())
1549 {
1550 node->getTest()->traverse(this);
1551 }
1552
1553 out << "; ";
1554
1555 if (node->getTerminal())
1556 {
1557 node->getTerminal()->traverse(this);
1558 }
1559
1560 out << ")\n"
1561 "{\n";
1562 }
1563
1564 if (node->getBody())
1565 {
1566 node->getBody()->traverse(this);
1567 }
1568
1569 out << "}\n";
1570
1571 if (!node->testFirst())
1572 {
1573 out << "while(\n";
1574
1575 node->getTest()->traverse(this);
1576
1577 out << ")";
1578 }
1579
1580 out << ";\n";
1581
1582 return false;
1583}
1584
1585bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1586{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001587 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001588
1589 switch (node->getFlowOp())
1590 {
daniel@transgaming.comf67f82e2010-03-17 03:58:54 +00001591 case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break;
1592 case EOpBreak: outputTriplet(visit, "break", NULL, NULL); break;
1593 case EOpContinue: outputTriplet(visit, "continue", NULL, NULL); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001594 case EOpReturn:
1595 if (visit == PreVisit)
1596 {
1597 if (node->getExpression())
1598 {
1599 out << "return ";
1600 }
1601 else
1602 {
1603 out << "return;\n";
1604 }
1605 }
1606 else if (visit == PostVisit)
1607 {
1608 out << ";\n";
1609 }
1610 break;
1611 default: UNREACHABLE();
1612 }
1613
1614 return true;
1615}
1616
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001617bool OutputHLSL::isSingleStatement(TIntermNode *node)
1618{
1619 TIntermAggregate *aggregate = node->getAsAggregate();
1620
1621 if (aggregate)
1622 {
1623 if (aggregate->getOp() == EOpSequence)
1624 {
1625 return false;
1626 }
1627 else
1628 {
1629 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1630 {
1631 if (!isSingleStatement(*sit))
1632 {
1633 return false;
1634 }
1635 }
1636
1637 return true;
1638 }
1639 }
1640
1641 return true;
1642}
1643
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001644// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1645bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1646{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001647 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001648
1649 // Parse loops of the form:
1650 // for(int index = initial; index [comparator] limit; index += increment)
1651 TIntermSymbol *index = NULL;
1652 TOperator comparator = EOpNull;
1653 int initial = 0;
1654 int limit = 0;
1655 int increment = 0;
1656
1657 // Parse index name and intial value
1658 if (node->getInit())
1659 {
1660 TIntermAggregate *init = node->getInit()->getAsAggregate();
1661
1662 if (init)
1663 {
1664 TIntermSequence &sequence = init->getSequence();
1665 TIntermTyped *variable = sequence[0]->getAsTyped();
1666
1667 if (variable && variable->getQualifier() == EvqTemporary)
1668 {
1669 TIntermBinary *assign = variable->getAsBinaryNode();
1670
1671 if (assign->getOp() == EOpInitialize)
1672 {
1673 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1674 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1675
1676 if (symbol && constant)
1677 {
1678 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1679 {
1680 index = symbol;
1681 initial = constant->getUnionArrayPointer()[0].getIConst();
1682 }
1683 }
1684 }
1685 }
1686 }
1687 }
1688
1689 // Parse comparator and limit value
1690 if (index != NULL && node->getTest())
1691 {
1692 TIntermBinary *test = node->getTest()->getAsBinaryNode();
1693
1694 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1695 {
1696 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1697
1698 if (constant)
1699 {
1700 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1701 {
1702 comparator = test->getOp();
1703 limit = constant->getUnionArrayPointer()[0].getIConst();
1704 }
1705 }
1706 }
1707 }
1708
1709 // Parse increment
1710 if (index != NULL && comparator != EOpNull && node->getTerminal())
1711 {
1712 TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
1713 TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
1714
1715 if (binaryTerminal)
1716 {
1717 TOperator op = binaryTerminal->getOp();
1718 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1719
1720 if (constant)
1721 {
1722 if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
1723 {
1724 int value = constant->getUnionArrayPointer()[0].getIConst();
1725
1726 switch (op)
1727 {
1728 case EOpAddAssign: increment = value; break;
1729 case EOpSubAssign: increment = -value; break;
1730 default: UNIMPLEMENTED();
1731 }
1732 }
1733 }
1734 }
1735 else if (unaryTerminal)
1736 {
1737 TOperator op = unaryTerminal->getOp();
1738
1739 switch (op)
1740 {
1741 case EOpPostIncrement: increment = 1; break;
1742 case EOpPostDecrement: increment = -1; break;
1743 case EOpPreIncrement: increment = 1; break;
1744 case EOpPreDecrement: increment = -1; break;
1745 default: UNIMPLEMENTED();
1746 }
1747 }
1748 }
1749
1750 if (index != NULL && comparator != EOpNull && increment != 0)
1751 {
1752 if (comparator == EOpLessThanEqual)
1753 {
1754 comparator = EOpLessThan;
1755 limit += 1;
1756 }
1757
1758 if (comparator == EOpLessThan)
1759 {
1760 int iterations = (limit - initial + 1) / increment;
1761
1762 if (iterations <= 255)
1763 {
1764 return false; // Not an excessive loop
1765 }
1766
1767 while (iterations > 0)
1768 {
1769 int remainder = (limit - initial + 1) % increment;
alokp@chromium.org47c058c2010-04-13 15:30:05 +00001770 int clampedLimit = initial + increment * std::min(255, iterations) - 1 - remainder;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001771
1772 // for(int index = initial; index < clampedLimit; index += increment)
1773
1774 out << "for(int ";
1775 index->traverse(this);
1776 out << " = ";
1777 out << initial;
1778
1779 out << "; ";
1780 index->traverse(this);
1781 out << " < ";
1782 out << clampedLimit;
1783
1784 out << "; ";
1785 index->traverse(this);
1786 out << " += ";
1787 out << increment;
1788 out << ")\n"
1789 "{\n";
1790
1791 if (node->getBody())
1792 {
1793 node->getBody()->traverse(this);
1794 }
1795
1796 out << "}\n";
1797
1798 initial += 255 * increment;
1799 iterations -= 255;
1800 }
1801
1802 return true;
1803 }
1804 else UNIMPLEMENTED();
1805 }
1806
1807 return false; // Not handled as an excessive loop
1808}
1809
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001810void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
1811{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001812 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001813
1814 if (visit == PreVisit && preString)
1815 {
1816 out << preString;
1817 }
1818 else if (visit == InVisit && inString)
1819 {
1820 out << inString;
1821 }
1822 else if (visit == PostVisit && postString)
1823 {
1824 out << postString;
1825 }
1826}
1827
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001828TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1829{
1830 TQualifier qualifier = symbol->getQualifier();
1831 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001832 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001833
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001834 if (name.empty()) // HLSL demands named arguments, also for prototypes
1835 {
1836 name = "x" + str(mArgumentIndex++);
1837 }
1838 else
1839 {
1840 name = decorate(name);
1841 }
1842
1843 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001844}
1845
1846TString OutputHLSL::qualifierString(TQualifier qualifier)
1847{
1848 switch(qualifier)
1849 {
1850 case EvqIn: return "in";
1851 case EvqOut: return "out";
1852 case EvqInOut: return "inout";
1853 case EvqConstReadOnly: return "const";
1854 default: UNREACHABLE();
1855 }
1856
1857 return "";
1858}
1859
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001860TString OutputHLSL::typeString(const TType &type)
1861{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001862 if (type.getBasicType() == EbtStruct)
1863 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001864 return decorate(type.getTypeName());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001865 }
1866 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001867 {
1868 switch (type.getNominalSize())
1869 {
1870 case 2: return "float2x2";
1871 case 3: return "float3x3";
1872 case 4: return "float4x4";
1873 }
1874 }
1875 else
1876 {
1877 switch (type.getBasicType())
1878 {
1879 case EbtFloat:
1880 switch (type.getNominalSize())
1881 {
1882 case 1: return "float";
1883 case 2: return "float2";
1884 case 3: return "float3";
1885 case 4: return "float4";
1886 }
1887 case EbtInt:
1888 switch (type.getNominalSize())
1889 {
1890 case 1: return "int";
1891 case 2: return "int2";
1892 case 3: return "int3";
1893 case 4: return "int4";
1894 }
1895 case EbtBool:
1896 switch (type.getNominalSize())
1897 {
1898 case 1: return "bool";
1899 case 2: return "bool2";
1900 case 3: return "bool3";
1901 case 4: return "bool4";
1902 }
1903 case EbtVoid:
1904 return "void";
1905 case EbtSampler2D:
1906 return "sampler2D";
1907 case EbtSamplerCube:
1908 return "samplerCUBE";
1909 }
1910 }
1911
1912 UNIMPLEMENTED(); // FIXME
1913 return "<unknown type>";
1914}
1915
1916TString OutputHLSL::arrayString(const TType &type)
1917{
1918 if (!type.isArray())
1919 {
1920 return "";
1921 }
1922
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001923 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001924}
1925
1926TString OutputHLSL::initializer(const TType &type)
1927{
1928 TString string;
1929
1930 int arraySize = type.isArray() ? type.getArraySize() : 1;
1931
1932 if (type.isArray())
1933 {
1934 string += "{";
1935 }
1936
1937 for (int element = 0; element < arraySize; element++)
1938 {
1939 string += typeString(type) + "(";
1940
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001941 for (int component = 0; component < type.getInstanceSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001942 {
1943 string += "0";
1944
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001945 if (component < type.getInstanceSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001946 {
1947 string += ", ";
1948 }
1949 }
1950
1951 string += ")";
1952
1953 if (element < arraySize - 1)
1954 {
1955 string += ", ";
1956 }
1957 }
1958
1959 if (type.isArray())
1960 {
1961 string += "}";
1962 }
1963
1964 return string;
1965}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001966
1967TString OutputHLSL::decorate(const TString &string)
1968{
1969 if (string.substr(0, 3) != "gl_")
1970 {
1971 return "_" + string;
1972 }
1973 else
1974 {
1975 return string;
1976 }
1977}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001978}