blob: a3cd610893b305084ca17fb880821857a386b443 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00007#include "compiler/OutputHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00008
alokp@chromium.org91b72322010-06-02 15:50:56 +00009#include "compiler/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "compiler/InfoSink.h"
11#include "compiler/UnfoldSelect.h"
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +000012#include "compiler/SearchSymbol.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
apatrick@chromium.orgbad6c2a2010-07-20 20:19:51 +000014#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000015#include <algorithm>
16
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017namespace sh
18{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000019// Integer to TString conversion
20TString str(int i)
21{
22 char buffer[20];
23 sprintf(buffer, "%d", i);
24 return buffer;
25}
26
daniel@transgaming.com950f9932010-04-13 03:26:14 +000027OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000029 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000030 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000031
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000032 mUsesTexture2D = false;
33 mUsesTexture2D_bias = false;
34 mUsesTexture2DProj = false;
35 mUsesTexture2DProj_bias = false;
36 mUsesTextureCube = false;
37 mUsesTextureCube_bias = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000038 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000039 mUsesFragCoord = false;
40 mUsesPointCoord = false;
41 mUsesFrontFacing = false;
42 mUsesPointSize = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000043 mUsesXor = false;
44 mUsesMod1 = false;
45 mUsesMod2 = false;
46 mUsesMod3 = false;
47 mUsesMod4 = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000048 mUsesFaceforward1 = false;
49 mUsesFaceforward2 = false;
50 mUsesFaceforward3 = false;
51 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000052 mUsesEqualMat2 = false;
53 mUsesEqualMat3 = false;
54 mUsesEqualMat4 = false;
55 mUsesEqualVec2 = false;
56 mUsesEqualVec3 = false;
57 mUsesEqualVec4 = false;
58 mUsesEqualIVec2 = false;
59 mUsesEqualIVec3 = false;
60 mUsesEqualIVec4 = false;
61 mUsesEqualBVec2 = false;
62 mUsesEqualBVec3 = false;
63 mUsesEqualBVec4 = false;
daniel@transgaming.com0f189612010-05-07 13:03:36 +000064 mUsesAtan2 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000065
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +000066 mScopeDepth = 0;
67
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +000068 mUniqueIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069}
70
daniel@transgaming.comb5875982010-04-15 20:44:53 +000071OutputHLSL::~OutputHLSL()
72{
73 delete mUnfoldSelect;
74}
75
daniel@transgaming.com950f9932010-04-13 03:26:14 +000076void OutputHLSL::output()
77{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000078 mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
daniel@transgaming.com950f9932010-04-13 03:26:14 +000079 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000080
81 mContext.infoSink.obj << mHeader.c_str();
82 mContext.infoSink.obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000083}
84
daniel@transgaming.comb5875982010-04-15 20:44:53 +000085TInfoSinkBase &OutputHLSL::getBodyStream()
86{
87 return mBody;
88}
89
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +000090int OutputHLSL::vectorSize(const TType &type) const
91{
92 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
93 int arraySize = type.isArray() ? type.getArraySize() : 1;
94
95 return elementSize * arraySize;
96}
97
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000098void OutputHLSL::header()
99{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000100 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000101 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000103 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000104 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000105 out << *structDeclaration;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000106 }
107
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000108 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000109 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000110 out << *constructor;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000111 }
112
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000113 if (shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114 {
115 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000116 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000118 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000119 int semanticIndex = 0;
120
121 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
122 {
123 const TSymbol *symbol = (*namedSymbol).second;
124 const TString &name = symbol->getName();
125
126 if (symbol->isVariable())
127 {
128 const TVariable *variable = static_cast<const TVariable*>(symbol);
129 const TType &type = variable->getType();
130 TQualifier qualifier = type.getQualifier();
131
132 if (qualifier == EvqUniform)
133 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000134 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
135 {
136 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
137 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 }
139 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
140 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000141 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
142 {
143 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000144 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000145
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000146 semanticIndex += type.isArray() ? type.getArraySize() : 1;
147 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000149 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000150 {
151 // Globals are declared and intialized as an aggregate node
152 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000153 else if (qualifier == EvqConst)
154 {
155 // Constants are repeated as literals where used
156 }
157 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158 }
159 }
160
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000161 out << "// Varyings\n";
162 out << varyings;
163 out << "\n"
164 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
165
166 if (mUsesFragCoord)
167 {
168 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
169 }
170
171 if (mUsesPointCoord)
172 {
173 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
174 }
175
176 if (mUsesFrontFacing)
177 {
178 out << "static bool gl_FrontFacing = false;\n";
179 }
180
181 out << "\n";
182
183 if (mUsesFragCoord)
184 {
daniel@transgaming.com4f921eb2010-07-28 19:20:44 +0000185 out << "uniform float4 dx_Viewport;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000186 "uniform float2 dx_Depth;\n";
187 }
188
189 if (mUsesFrontFacing)
190 {
191 out << "uniform bool dx_PointsOrLines;\n"
192 "uniform bool dx_FrontCCW;\n";
193 }
194
195 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000197 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000198
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000199 // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
200 // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
201 // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
202 // convention, the Y coordinate passed to these functions is adjusted to compensate.
203 //
204 // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
205 //
206 // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
207 // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
208 //
209 // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
210 // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
211 // +Y and -Y faces everywhere else throughout the code.
212
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000213 if (mUsesTexture2D)
214 {
215 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
216 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000217 " return tex2D(s, float2(t.x, 1 - t.y));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000218 "}\n"
219 "\n";
220 }
221
222 if (mUsesTexture2D_bias)
223 {
224 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
225 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000226 " return tex2Dbias(s, float4(t.x, 1 - t.y, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000227 "}\n"
228 "\n";
229 }
230
231 if (mUsesTexture2DProj)
232 {
233 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
234 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000235 " return tex2Dproj(s, float4(t.x, t.z - t.y, 0, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000236 "}\n"
237 "\n"
238 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
239 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000240 " return tex2Dproj(s, float4(t.x, t.w - t.y, t.z, t.w));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000241 "}\n"
242 "\n";
243 }
244
245 if (mUsesTexture2DProj_bias)
246 {
247 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
248 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000249 " return tex2Dbias(s, float4(t.x / t.z, 1 - (t.y / t.z), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000250 "}\n"
251 "\n"
252 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
253 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000254 " return tex2Dbias(s, float4(t.x / t.w, 1 - (t.y / t.w), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000255 "}\n"
256 "\n";
257 }
258
259 if (mUsesTextureCube)
260 {
261 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
262 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000263 " return texCUBE(s, float3(t.x, -t.y, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000264 "}\n"
265 "\n";
266 }
267
268 if (mUsesTextureCube_bias)
269 {
270 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
271 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000272 " return texCUBEbias(s, float4(t.x, -t.y, t.z, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000273 "}\n"
274 "\n";
275 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000277 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 {
279 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000280 TString attributes;
281 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000283 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284
285 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
286 {
287 const TSymbol *symbol = (*namedSymbol).second;
288 const TString &name = symbol->getName();
289
290 if (symbol->isVariable())
291 {
292 const TVariable *variable = static_cast<const TVariable*>(symbol);
293 const TType &type = variable->getType();
294 TQualifier qualifier = type.getQualifier();
295
296 if (qualifier == EvqUniform)
297 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000298 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
299 {
300 uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
301 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302 }
303 else if (qualifier == EvqAttribute)
304 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000305 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
306 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000307 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000308 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309 }
310 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
311 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000312 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
313 {
314 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000315 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000316 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000318 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000320 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000322 else if (qualifier == EvqConst)
323 {
324 // Constants are repeated as literals where used
325 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 else UNREACHABLE();
327 }
328 }
329
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000330 out << "// Attributes\n";
331 out << attributes;
332 out << "\n"
333 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
334
335 if (mUsesPointSize)
336 {
337 out << "static float gl_PointSize = float(1);\n";
338 }
339
340 out << "\n"
341 "// Varyings\n";
342 out << varyings;
343 out << "\n"
344 "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000345 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347 out << "\n";
348 }
349
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000350 if (mUsesFragCoord)
351 {
352 out << "#define GL_USES_FRAG_COORD\n";
353 }
354
355 if (mUsesPointCoord)
356 {
357 out << "#define GL_USES_POINT_COORD\n";
358 }
359
360 if (mUsesFrontFacing)
361 {
362 out << "#define GL_USES_FRONT_FACING\n";
363 }
364
365 if (mUsesPointSize)
366 {
367 out << "#define GL_USES_POINT_SIZE\n";
368 }
369
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000370 if (mUsesDepthRange)
371 {
372 out << "struct gl_DepthRangeParameters\n"
373 "{\n"
374 " float near;\n"
375 " float far;\n"
376 " float diff;\n"
377 "};\n"
378 "\n"
daniel@transgaming.com31754962010-11-28 02:02:52 +0000379 "uniform float3 dx_DepthRange;"
380 "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000381 "\n";
382 }
383
384 if (mUsesXor)
385 {
386 out << "bool xor(bool p, bool q)\n"
387 "{\n"
388 " return (p || q) && !(p && q);\n"
389 "}\n"
390 "\n";
391 }
392
393 if (mUsesMod1)
394 {
395 out << "float mod(float x, float y)\n"
396 "{\n"
397 " return x - y * floor(x / y);\n"
398 "}\n"
399 "\n";
400 }
401
402 if (mUsesMod2)
403 {
404 out << "float2 mod(float2 x, float y)\n"
405 "{\n"
406 " return x - y * floor(x / y);\n"
407 "}\n"
408 "\n";
409 }
410
411 if (mUsesMod3)
412 {
413 out << "float3 mod(float3 x, float y)\n"
414 "{\n"
415 " return x - y * floor(x / y);\n"
416 "}\n"
417 "\n";
418 }
419
420 if (mUsesMod4)
421 {
422 out << "float4 mod(float4 x, float y)\n"
423 "{\n"
424 " return x - y * floor(x / y);\n"
425 "}\n"
426 "\n";
427 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000428
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000429 if (mUsesFaceforward1)
430 {
431 out << "float faceforward(float N, float I, float Nref)\n"
432 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000433 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000434 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000435 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000436 " }\n"
437 " else\n"
438 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000439 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000440 " }\n"
441 "}\n"
442 "\n";
443 }
444
445 if (mUsesFaceforward2)
446 {
447 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
448 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000449 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000450 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000451 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000452 " }\n"
453 " else\n"
454 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000455 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000456 " }\n"
457 "}\n"
458 "\n";
459 }
460
461 if (mUsesFaceforward3)
462 {
463 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
464 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000465 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000466 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000467 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000468 " }\n"
469 " else\n"
470 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000471 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000472 " }\n"
473 "}\n"
474 "\n";
475 }
476
477 if (mUsesFaceforward4)
478 {
479 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
480 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000481 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000482 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000483 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000484 " }\n"
485 " else\n"
486 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000487 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000488 " }\n"
489 "}\n"
490 "\n";
491 }
492
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000493 if (mUsesEqualMat2)
494 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000495 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000496 "{\n"
497 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
498 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
499 "}\n";
500 }
501
502 if (mUsesEqualMat3)
503 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000504 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000505 "{\n"
506 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
507 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
508 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
509 "}\n";
510 }
511
512 if (mUsesEqualMat4)
513 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000514 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000515 "{\n"
516 " 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"
517 " 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"
518 " 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"
519 " 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"
520 "}\n";
521 }
522
523 if (mUsesEqualVec2)
524 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000525 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000526 "{\n"
527 " return v.x == u.x && v.y == u.y;\n"
528 "}\n";
529 }
530
531 if (mUsesEqualVec3)
532 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000533 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000534 "{\n"
535 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
536 "}\n";
537 }
538
539 if (mUsesEqualVec4)
540 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000541 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000542 "{\n"
543 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
544 "}\n";
545 }
546
547 if (mUsesEqualIVec2)
548 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000549 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000550 "{\n"
551 " return v.x == u.x && v.y == u.y;\n"
552 "}\n";
553 }
554
555 if (mUsesEqualIVec3)
556 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000557 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000558 "{\n"
559 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
560 "}\n";
561 }
562
563 if (mUsesEqualIVec4)
564 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000565 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000566 "{\n"
567 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
568 "}\n";
569 }
570
571 if (mUsesEqualBVec2)
572 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000573 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000574 "{\n"
575 " return v.x == u.x && v.y == u.y;\n"
576 "}\n";
577 }
578
579 if (mUsesEqualBVec3)
580 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000581 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000582 "{\n"
583 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
584 "}\n";
585 }
586
587 if (mUsesEqualBVec4)
588 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000589 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000590 "{\n"
591 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
592 "}\n";
593 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000594
595 if (mUsesAtan2)
596 {
597 out << "float atanyx(float y, float x)\n"
598 "{\n"
599 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
600 " return atan2(y, x);\n"
601 "}\n";
602 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000603}
604
605void OutputHLSL::visitSymbol(TIntermSymbol *node)
606{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000607 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608
609 TString name = node->getSymbol();
610
611 if (name == "gl_FragColor")
612 {
613 out << "gl_Color[0]";
614 }
615 else if (name == "gl_FragData")
616 {
617 out << "gl_Color";
618 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000619 else if (name == "gl_DepthRange")
620 {
621 mUsesDepthRange = true;
622 out << name;
623 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000624 else if (name == "gl_FragCoord")
625 {
626 mUsesFragCoord = true;
627 out << name;
628 }
629 else if (name == "gl_PointCoord")
630 {
631 mUsesPointCoord = true;
632 out << name;
633 }
634 else if (name == "gl_FrontFacing")
635 {
636 mUsesFrontFacing = true;
637 out << name;
638 }
639 else if (name == "gl_PointSize")
640 {
641 mUsesPointSize = true;
642 out << name;
643 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644 else
645 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000646 TQualifier qualifier = node->getQualifier();
647
648 if (qualifier == EvqUniform)
649 {
650 mReferencedUniforms.insert(name.c_str());
651 }
652 else if (qualifier == EvqAttribute)
653 {
654 mReferencedAttributes.insert(name.c_str());
655 }
656 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
657 {
658 mReferencedVaryings.insert(name.c_str());
659 }
660
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000661 out << decorate(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662 }
663}
664
665bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
666{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000667 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668
669 switch (node->getOp())
670 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000671 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000672 case EOpInitialize:
673 if (visit == PreVisit)
674 {
675 // GLSL allows to write things like "float x = x;" where a new variable x is defined
676 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
677 // new variable is created before the assignment is evaluated), so we need to convert
678 // this to "float t = x, x = t;".
679
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000680 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
681 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000682
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000683 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
684 expression->traverse(&searchSymbol);
685 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000686
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000687 if (sameSymbol)
688 {
689 // Type already printed
690 out << "t" + str(mUniqueIndex) + " = ";
691 expression->traverse(this);
692 out << ", ";
693 symbolNode->traverse(this);
694 out << " = t" + str(mUniqueIndex);
695
696 mUniqueIndex++;
697 return false;
698 }
699 }
700 else if (visit == InVisit)
701 {
702 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000703 }
704 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000705 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
706 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
707 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
708 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
709 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
710 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000711 if (visit == PreVisit)
712 {
713 out << "(";
714 }
715 else if (visit == InVisit)
716 {
717 out << " = mul(";
718 node->getLeft()->traverse(this);
719 out << ", transpose(";
720 }
721 else
722 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000723 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000724 }
725 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000726 case EOpMatrixTimesMatrixAssign:
727 if (visit == PreVisit)
728 {
729 out << "(";
730 }
731 else if (visit == InVisit)
732 {
733 out << " = mul(";
734 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000735 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000736 }
737 else
738 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000739 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000740 }
741 break;
742 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000743 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
744 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000745 case EOpIndexDirectStruct:
746 if (visit == InVisit)
747 {
748 out << "." + node->getType().getFieldName();
749
750 return false;
751 }
752 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000753 case EOpVectorSwizzle:
754 if (visit == InVisit)
755 {
756 out << ".";
757
758 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
759
760 if (swizzle)
761 {
762 TIntermSequence &sequence = swizzle->getSequence();
763
764 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
765 {
766 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
767
768 if (element)
769 {
770 int i = element->getUnionArrayPointer()[0].getIConst();
771
772 switch (i)
773 {
774 case 0: out << "x"; break;
775 case 1: out << "y"; break;
776 case 2: out << "z"; break;
777 case 3: out << "w"; break;
778 default: UNREACHABLE();
779 }
780 }
781 else UNREACHABLE();
782 }
783 }
784 else UNREACHABLE();
785
786 return false; // Fully processed
787 }
788 break;
789 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
790 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
791 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
792 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000793 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000794 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000795 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000796 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000797 if (node->getOp() == EOpEqual)
798 {
799 outputTriplet(visit, "(", " == ", ")");
800 }
801 else
802 {
803 outputTriplet(visit, "(", " != ", ")");
804 }
805 }
806 else if (node->getLeft()->getBasicType() == EbtStruct)
807 {
808 if (node->getOp() == EOpEqual)
809 {
810 out << "(";
811 }
812 else
813 {
814 out << "!(";
815 }
816
817 const TTypeList *fields = node->getLeft()->getType().getStruct();
818
819 for (size_t i = 0; i < fields->size(); i++)
820 {
821 const TType *fieldType = (*fields)[i].type;
822
823 node->getLeft()->traverse(this);
824 out << "." + fieldType->getFieldName() + " == ";
825 node->getRight()->traverse(this);
826 out << "." + fieldType->getFieldName();
827
828 if (i < fields->size() - 1)
829 {
830 out << " && ";
831 }
832 }
833
834 out << ")";
835
836 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000837 }
838 else
839 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000840 if (node->getLeft()->isMatrix())
841 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000842 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000843 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000844 case 2: mUsesEqualMat2 = true; break;
845 case 3: mUsesEqualMat3 = true; break;
846 case 4: mUsesEqualMat4 = true; break;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000847 default: UNREACHABLE();
848 }
849 }
850 else if (node->getLeft()->isVector())
851 {
852 switch (node->getLeft()->getBasicType())
853 {
854 case EbtFloat:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000855 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000856 {
857 case 2: mUsesEqualVec2 = true; break;
858 case 3: mUsesEqualVec3 = true; break;
859 case 4: mUsesEqualVec4 = true; break;
860 default: UNREACHABLE();
861 }
862 break;
863 case EbtInt:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000864 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000865 {
866 case 2: mUsesEqualIVec2 = true; break;
867 case 3: mUsesEqualIVec3 = true; break;
868 case 4: mUsesEqualIVec4 = true; break;
869 default: UNREACHABLE();
870 }
871 break;
872 case EbtBool:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000873 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000874 {
875 case 2: mUsesEqualBVec2 = true; break;
876 case 3: mUsesEqualBVec3 = true; break;
877 case 4: mUsesEqualBVec4 = true; break;
878 default: UNREACHABLE();
879 }
880 break;
881 default: UNREACHABLE();
882 }
883 }
884 else UNREACHABLE();
885
886 if (node->getOp() == EOpEqual)
887 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000888 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000889 }
890 else
891 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000892 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000893 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000894 }
895 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
897 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
898 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
899 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
900 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000901 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000902 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
903 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +0000904 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000905 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000906 case EOpLogicalXor:
907 mUsesXor = true;
908 outputTriplet(visit, "xor(", ", ", ")");
909 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000910 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
911 default: UNREACHABLE();
912 }
913
914 return true;
915}
916
917bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
918{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000919 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920
921 switch (node->getOp())
922 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000923 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
924 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
925 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
926 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
927 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
928 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
929 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930 case EOpConvIntToBool:
931 case EOpConvFloatToBool:
932 switch (node->getOperand()->getType().getNominalSize())
933 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000934 case 1: outputTriplet(visit, "bool(", "", ")"); break;
935 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
936 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
937 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938 default: UNREACHABLE();
939 }
940 break;
941 case EOpConvBoolToFloat:
942 case EOpConvIntToFloat:
943 switch (node->getOperand()->getType().getNominalSize())
944 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000945 case 1: outputTriplet(visit, "float(", "", ")"); break;
946 case 2: outputTriplet(visit, "float2(", "", ")"); break;
947 case 3: outputTriplet(visit, "float3(", "", ")"); break;
948 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949 default: UNREACHABLE();
950 }
951 break;
952 case EOpConvFloatToInt:
953 case EOpConvBoolToInt:
954 switch (node->getOperand()->getType().getNominalSize())
955 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000956 case 1: outputTriplet(visit, "int(", "", ")"); break;
957 case 2: outputTriplet(visit, "int2(", "", ")"); break;
958 case 3: outputTriplet(visit, "int3(", "", ")"); break;
959 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960 default: UNREACHABLE();
961 }
962 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000963 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
964 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
965 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
966 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
967 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
968 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
969 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
970 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
971 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
972 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
973 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
974 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
975 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
976 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
977 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
978 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
979 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
980 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
981 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
982 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
983 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +0000984 case EOpDFdx: outputTriplet(visit, "ddx(", "", ")"); break;
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000985 case EOpDFdy: outputTriplet(visit, "(-ddy(", "", "))"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +0000986 case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000987 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
988 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000989 default: UNREACHABLE();
990 }
991
992 return true;
993}
994
995bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
996{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000997 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000998 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001000 switch (node->getOp())
1001 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001002 case EOpSequence:
1003 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001004 if (mInsideFunction)
1005 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001006 outputLineDirective(node->getLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001007 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001008
1009 mScopeDepth++;
1010
1011 if (mScopeBracket.size() < mScopeDepth)
1012 {
1013 mScopeBracket.push_back(0); // New scope level
1014 }
1015 else
1016 {
1017 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
1018 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001019 }
1020
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001021 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1022 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001023 outputLineDirective((*sit)->getLine());
1024
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001025 if (isSingleStatement(*sit))
1026 {
1027 mUnfoldSelect->traverse(*sit);
1028 }
1029
1030 (*sit)->traverse(this);
1031
1032 out << ";\n";
1033 }
1034
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001035 if (mInsideFunction)
1036 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001037 outputLineDirective(node->getEndLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001038 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001039
1040 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001041 }
1042
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001043 return false;
1044 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045 case EOpDeclaration:
1046 if (visit == PreVisit)
1047 {
1048 TIntermSequence &sequence = node->getSequence();
1049 TIntermTyped *variable = sequence[0]->getAsTyped();
1050 bool visit = true;
1051
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001052 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001053 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001054 if (variable->getType().getStruct())
1055 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001056 addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001057 }
1058
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001059 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001060 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001061 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001062 {
1063 out << "static ";
1064 }
1065
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001066 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001068 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001070 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001071
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001072 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001073 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001074 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001075 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001076 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001077 }
1078 else
1079 {
1080 (*sit)->traverse(this);
1081 }
1082
1083 if (visit && this->inVisit)
1084 {
1085 if (*sit != sequence.back())
1086 {
1087 visit = this->visitAggregate(InVisit, node);
1088 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089 }
1090 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001091
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001092 if (visit && this->postVisit)
1093 {
1094 this->visitAggregate(PostVisit, node);
1095 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001097 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1098 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001099 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001100 }
1101 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001102 }
1103
1104 return false;
1105 }
1106 else if (visit == InVisit)
1107 {
1108 out << ", ";
1109 }
1110 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001111 case EOpPrototype:
1112 if (visit == PreVisit)
1113 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001114 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001115
1116 TIntermSequence &arguments = node->getSequence();
1117
1118 for (unsigned int i = 0; i < arguments.size(); i++)
1119 {
1120 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1121
1122 if (symbol)
1123 {
1124 out << argumentString(symbol);
1125
1126 if (i < arguments.size() - 1)
1127 {
1128 out << ", ";
1129 }
1130 }
1131 else UNREACHABLE();
1132 }
1133
1134 out << ");\n";
1135
1136 return false;
1137 }
1138 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001139 case EOpComma: outputTriplet(visit, "", ", ", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140 case EOpFunction:
1141 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001142 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143
1144 if (visit == PreVisit)
1145 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001146 out << typeString(node->getType()) << " ";
1147
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148 if (name == "main")
1149 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001150 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001151 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001152 else
1153 {
1154 out << decorate(name) << "(";
1155 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001156
1157 TIntermSequence &sequence = node->getSequence();
1158 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1159
1160 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001161 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001162 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001164 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001165 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001166 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001167
1168 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001169 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001170 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001171 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001172 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001173 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001174 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001175
1176 sequence.erase(sequence.begin());
1177
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001178 out << ")\n";
1179
1180 outputLineDirective(node->getLine());
1181 out << "{\n";
1182
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001183 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001184 }
1185 else if (visit == PostVisit)
1186 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001187 outputLineDirective(node->getEndLine());
daniel@transgaming.com63691862010-04-29 03:32:42 +00001188 out << "}\n";
1189
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001190 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001191 }
1192 }
1193 break;
1194 case EOpFunctionCall:
1195 {
1196 if (visit == PreVisit)
1197 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001198 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199
1200 if (node->isUserDefined())
1201 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001202 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203 }
1204 else
1205 {
1206 if (name == "texture2D")
1207 {
1208 if (node->getSequence().size() == 2)
1209 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001210 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211 }
1212 else if (node->getSequence().size() == 3)
1213 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001214 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215 }
1216 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001217
1218 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001219 }
1220 else if (name == "texture2DProj")
1221 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001222 if (node->getSequence().size() == 2)
1223 {
1224 mUsesTexture2DProj = true;
1225 }
1226 else if (node->getSequence().size() == 3)
1227 {
1228 mUsesTexture2DProj_bias = true;
1229 }
1230 else UNREACHABLE();
1231
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001232 out << "gl_texture2DProj(";
1233 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001234 else if (name == "textureCube")
1235 {
1236 if (node->getSequence().size() == 2)
1237 {
1238 mUsesTextureCube = true;
1239 }
1240 else if (node->getSequence().size() == 3)
1241 {
1242 mUsesTextureCube_bias = true;
1243 }
1244 else UNREACHABLE();
1245
1246 out << "gl_textureCube(";
1247 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001248 else if (name == "texture2DLod")
1249 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001250 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001251 }
1252 else if (name == "texture2DProjLod")
1253 {
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001254 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001255 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001256 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001257 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001258 UNIMPLEMENTED(); // Requires the vertex shader texture sampling extension
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001260 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261 }
1262 }
1263 else if (visit == InVisit)
1264 {
1265 out << ", ";
1266 }
1267 else
1268 {
1269 out << ")";
1270 }
1271 }
1272 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001273 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001274 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001275 addConstructor(node->getType(), "vec1", &node->getSequence());
1276 outputTriplet(visit, "vec1(", "", ")");
1277 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001278 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001279 addConstructor(node->getType(), "vec2", &node->getSequence());
1280 outputTriplet(visit, "vec2(", ", ", ")");
1281 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001282 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001283 addConstructor(node->getType(), "vec3", &node->getSequence());
1284 outputTriplet(visit, "vec3(", ", ", ")");
1285 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001286 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001287 addConstructor(node->getType(), "vec4", &node->getSequence());
1288 outputTriplet(visit, "vec4(", ", ", ")");
1289 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001290 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001291 addConstructor(node->getType(), "bvec1", &node->getSequence());
1292 outputTriplet(visit, "bvec1(", "", ")");
1293 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001294 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001295 addConstructor(node->getType(), "bvec2", &node->getSequence());
1296 outputTriplet(visit, "bvec2(", ", ", ")");
1297 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001298 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001299 addConstructor(node->getType(), "bvec3", &node->getSequence());
1300 outputTriplet(visit, "bvec3(", ", ", ")");
1301 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001302 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001303 addConstructor(node->getType(), "bvec4", &node->getSequence());
1304 outputTriplet(visit, "bvec4(", ", ", ")");
1305 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001306 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001307 addConstructor(node->getType(), "ivec1", &node->getSequence());
1308 outputTriplet(visit, "ivec1(", "", ")");
1309 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001310 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001311 addConstructor(node->getType(), "ivec2", &node->getSequence());
1312 outputTriplet(visit, "ivec2(", ", ", ")");
1313 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001314 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001315 addConstructor(node->getType(), "ivec3", &node->getSequence());
1316 outputTriplet(visit, "ivec3(", ", ", ")");
1317 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001318 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001319 addConstructor(node->getType(), "ivec4", &node->getSequence());
1320 outputTriplet(visit, "ivec4(", ", ", ")");
1321 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001322 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001323 addConstructor(node->getType(), "mat2", &node->getSequence());
1324 outputTriplet(visit, "mat2(", ", ", ")");
1325 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001326 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001327 addConstructor(node->getType(), "mat3", &node->getSequence());
1328 outputTriplet(visit, "mat3(", ", ", ")");
1329 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001330 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001331 addConstructor(node->getType(), "mat4", &node->getSequence());
1332 outputTriplet(visit, "mat4(", ", ", ")");
1333 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001334 case EOpConstructStruct:
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001335 addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1336 outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001337 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001338 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1339 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1340 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1341 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1342 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1343 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001344 case EOpMod:
1345 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001346 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001347 {
1348 case 1: mUsesMod1 = true; break;
1349 case 2: mUsesMod2 = true; break;
1350 case 3: mUsesMod3 = true; break;
1351 case 4: mUsesMod4 = true; break;
1352 default: UNREACHABLE();
1353 }
1354
1355 outputTriplet(visit, "mod(", ", ", ")");
1356 }
1357 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001358 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001359 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001360 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
1361 mUsesAtan2 = true;
1362 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001363 break;
1364 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1365 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1366 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1367 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1368 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1369 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1370 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1371 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1372 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001373 case EOpFaceForward:
1374 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001375 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001376 {
1377 case 1: mUsesFaceforward1 = true; break;
1378 case 2: mUsesFaceforward2 = true; break;
1379 case 3: mUsesFaceforward3 = true; break;
1380 case 4: mUsesFaceforward4 = true; break;
1381 default: UNREACHABLE();
1382 }
1383
1384 outputTriplet(visit, "faceforward(", ", ", ")");
1385 }
1386 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001387 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1388 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1389 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001390 default: UNREACHABLE();
1391 }
1392
1393 return true;
1394}
1395
1396bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1397{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001398 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001399
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001400 if (node->usesTernaryOperator())
1401 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001402 out << "t" << mUnfoldSelect->getTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001403 }
1404 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001405 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001406 mUnfoldSelect->traverse(node->getCondition());
1407
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001408 out << "if(";
1409
1410 node->getCondition()->traverse(this);
1411
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001412 out << ")\n";
1413
1414 outputLineDirective(node->getLine());
1415 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001416
daniel@transgaming.combb885322010-04-15 20:45:24 +00001417 if (node->getTrueBlock())
1418 {
1419 node->getTrueBlock()->traverse(this);
1420 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001421
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001422 outputLineDirective(node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001423 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001424
1425 if (node->getFalseBlock())
1426 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001427 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001428
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001429 outputLineDirective(node->getFalseBlock()->getLine());
1430 out << "{\n";
1431
1432 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001433 node->getFalseBlock()->traverse(this);
1434
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001435 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001436 out << ";}\n";
1437 }
1438 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001439
1440 return false;
1441}
1442
1443void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1444{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001445 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001446}
1447
1448bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1449{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001450 if (handleExcessiveLoop(node))
1451 {
1452 return false;
1453 }
1454
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001455 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001456
alokp@chromium.org52813552010-11-16 18:36:09 +00001457 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001458 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001459 out << "do\n";
1460
1461 outputLineDirective(node->getLine());
1462 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001463 }
1464 else
1465 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001466 if (node->getInit())
1467 {
1468 mUnfoldSelect->traverse(node->getInit());
1469 }
1470
alokp@chromium.org52813552010-11-16 18:36:09 +00001471 if (node->getCondition())
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001472 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001473 mUnfoldSelect->traverse(node->getCondition());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001474 }
1475
alokp@chromium.org52813552010-11-16 18:36:09 +00001476 if (node->getExpression())
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001477 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001478 mUnfoldSelect->traverse(node->getExpression());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001479 }
1480
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001481 out << "for(";
1482
1483 if (node->getInit())
1484 {
1485 node->getInit()->traverse(this);
1486 }
1487
1488 out << "; ";
1489
alokp@chromium.org52813552010-11-16 18:36:09 +00001490 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001491 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001492 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493 }
1494
1495 out << "; ";
1496
alokp@chromium.org52813552010-11-16 18:36:09 +00001497 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001498 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001499 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001500 }
1501
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001502 out << ")\n";
1503
1504 outputLineDirective(node->getLine());
1505 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001506 }
1507
1508 if (node->getBody())
1509 {
1510 node->getBody()->traverse(this);
1511 }
1512
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001513 outputLineDirective(node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001514 out << "}\n";
1515
alokp@chromium.org52813552010-11-16 18:36:09 +00001516 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001517 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001518 outputLineDirective(node->getCondition()->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001519 out << "while(\n";
1520
alokp@chromium.org52813552010-11-16 18:36:09 +00001521 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001522
1523 out << ")";
1524 }
1525
1526 out << ";\n";
1527
1528 return false;
1529}
1530
1531bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1532{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001533 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001534
1535 switch (node->getFlowOp())
1536 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001537 case EOpKill: outputTriplet(visit, "discard", "", ""); break;
1538 case EOpBreak: outputTriplet(visit, "break", "", ""); break;
1539 case EOpContinue: outputTriplet(visit, "continue", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001540 case EOpReturn:
1541 if (visit == PreVisit)
1542 {
1543 if (node->getExpression())
1544 {
1545 out << "return ";
1546 }
1547 else
1548 {
1549 out << "return;\n";
1550 }
1551 }
1552 else if (visit == PostVisit)
1553 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001554 if (node->getExpression())
1555 {
1556 out << ";\n";
1557 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001558 }
1559 break;
1560 default: UNREACHABLE();
1561 }
1562
1563 return true;
1564}
1565
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001566bool OutputHLSL::isSingleStatement(TIntermNode *node)
1567{
1568 TIntermAggregate *aggregate = node->getAsAggregate();
1569
1570 if (aggregate)
1571 {
1572 if (aggregate->getOp() == EOpSequence)
1573 {
1574 return false;
1575 }
1576 else
1577 {
1578 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1579 {
1580 if (!isSingleStatement(*sit))
1581 {
1582 return false;
1583 }
1584 }
1585
1586 return true;
1587 }
1588 }
1589
1590 return true;
1591}
1592
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001593// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1594bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1595{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001596 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001597
1598 // Parse loops of the form:
1599 // for(int index = initial; index [comparator] limit; index += increment)
1600 TIntermSymbol *index = NULL;
1601 TOperator comparator = EOpNull;
1602 int initial = 0;
1603 int limit = 0;
1604 int increment = 0;
1605
1606 // Parse index name and intial value
1607 if (node->getInit())
1608 {
1609 TIntermAggregate *init = node->getInit()->getAsAggregate();
1610
1611 if (init)
1612 {
1613 TIntermSequence &sequence = init->getSequence();
1614 TIntermTyped *variable = sequence[0]->getAsTyped();
1615
1616 if (variable && variable->getQualifier() == EvqTemporary)
1617 {
1618 TIntermBinary *assign = variable->getAsBinaryNode();
1619
1620 if (assign->getOp() == EOpInitialize)
1621 {
1622 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1623 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1624
1625 if (symbol && constant)
1626 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001627 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001628 {
1629 index = symbol;
1630 initial = constant->getUnionArrayPointer()[0].getIConst();
1631 }
1632 }
1633 }
1634 }
1635 }
1636 }
1637
1638 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00001639 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001640 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001641 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001642
1643 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1644 {
1645 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1646
1647 if (constant)
1648 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001649 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001650 {
1651 comparator = test->getOp();
1652 limit = constant->getUnionArrayPointer()[0].getIConst();
1653 }
1654 }
1655 }
1656 }
1657
1658 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00001659 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001660 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001661 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
1662 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001663
1664 if (binaryTerminal)
1665 {
1666 TOperator op = binaryTerminal->getOp();
1667 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1668
1669 if (constant)
1670 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001671 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001672 {
1673 int value = constant->getUnionArrayPointer()[0].getIConst();
1674
1675 switch (op)
1676 {
1677 case EOpAddAssign: increment = value; break;
1678 case EOpSubAssign: increment = -value; break;
1679 default: UNIMPLEMENTED();
1680 }
1681 }
1682 }
1683 }
1684 else if (unaryTerminal)
1685 {
1686 TOperator op = unaryTerminal->getOp();
1687
1688 switch (op)
1689 {
1690 case EOpPostIncrement: increment = 1; break;
1691 case EOpPostDecrement: increment = -1; break;
1692 case EOpPreIncrement: increment = 1; break;
1693 case EOpPreDecrement: increment = -1; break;
1694 default: UNIMPLEMENTED();
1695 }
1696 }
1697 }
1698
1699 if (index != NULL && comparator != EOpNull && increment != 0)
1700 {
1701 if (comparator == EOpLessThanEqual)
1702 {
1703 comparator = EOpLessThan;
1704 limit += 1;
1705 }
1706
1707 if (comparator == EOpLessThan)
1708 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001709 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001710
1711 if (iterations <= 255)
1712 {
1713 return false; // Not an excessive loop
1714 }
1715
1716 while (iterations > 0)
1717 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001718 int remainder = (limit - initial) % increment;
1719 int clampedLimit = initial + increment * std::min(255, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001720
1721 // for(int index = initial; index < clampedLimit; index += increment)
1722
1723 out << "for(int ";
1724 index->traverse(this);
1725 out << " = ";
1726 out << initial;
1727
1728 out << "; ";
1729 index->traverse(this);
1730 out << " < ";
1731 out << clampedLimit;
1732
1733 out << "; ";
1734 index->traverse(this);
1735 out << " += ";
1736 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001737 out << ")\n";
1738
1739 outputLineDirective(node->getLine());
1740 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001741
1742 if (node->getBody())
1743 {
1744 node->getBody()->traverse(this);
1745 }
1746
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001747 outputLineDirective(node->getLine());
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001748 out << "}\n";
1749
1750 initial += 255 * increment;
1751 iterations -= 255;
1752 }
1753
1754 return true;
1755 }
1756 else UNIMPLEMENTED();
1757 }
1758
1759 return false; // Not handled as an excessive loop
1760}
1761
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001762void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001763{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001764 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001765
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001766 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001767 {
1768 out << preString;
1769 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001770 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001771 {
1772 out << inString;
1773 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001774 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775 {
1776 out << postString;
1777 }
1778}
1779
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001780void OutputHLSL::outputLineDirective(int line)
1781{
1782 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
1783 {
1784 mBody << "#line " << line;
1785
1786 if (mContext.sourcePath)
1787 {
1788 mBody << " \"" << mContext.sourcePath << "\"";
1789 }
1790
1791 mBody << "\n";
1792 }
1793}
1794
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001795TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1796{
1797 TQualifier qualifier = symbol->getQualifier();
1798 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001799 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001800
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001801 if (name.empty()) // HLSL demands named arguments, also for prototypes
1802 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001803 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001804 }
1805 else
1806 {
1807 name = decorate(name);
1808 }
1809
1810 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001811}
1812
1813TString OutputHLSL::qualifierString(TQualifier qualifier)
1814{
1815 switch(qualifier)
1816 {
1817 case EvqIn: return "in";
1818 case EvqOut: return "out";
1819 case EvqInOut: return "inout";
1820 case EvqConstReadOnly: return "const";
1821 default: UNREACHABLE();
1822 }
1823
1824 return "";
1825}
1826
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001827TString OutputHLSL::typeString(const TType &type)
1828{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001829 if (type.getBasicType() == EbtStruct)
1830 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001831 if (type.getTypeName() != "")
1832 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001833 return structLookup(type.getTypeName());
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001834 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001835 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001836 {
1837 const TTypeList &fields = *type.getStruct();
1838
1839 TString string = "struct\n"
1840 "{\n";
1841
1842 for (unsigned int i = 0; i < fields.size(); i++)
1843 {
1844 const TType &field = *fields[i].type;
1845
1846 string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1847 }
1848
1849 string += "} ";
1850
1851 return string;
1852 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001853 }
1854 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001855 {
1856 switch (type.getNominalSize())
1857 {
1858 case 2: return "float2x2";
1859 case 3: return "float3x3";
1860 case 4: return "float4x4";
1861 }
1862 }
1863 else
1864 {
1865 switch (type.getBasicType())
1866 {
1867 case EbtFloat:
1868 switch (type.getNominalSize())
1869 {
1870 case 1: return "float";
1871 case 2: return "float2";
1872 case 3: return "float3";
1873 case 4: return "float4";
1874 }
1875 case EbtInt:
1876 switch (type.getNominalSize())
1877 {
1878 case 1: return "int";
1879 case 2: return "int2";
1880 case 3: return "int3";
1881 case 4: return "int4";
1882 }
1883 case EbtBool:
1884 switch (type.getNominalSize())
1885 {
1886 case 1: return "bool";
1887 case 2: return "bool2";
1888 case 3: return "bool3";
1889 case 4: return "bool4";
1890 }
1891 case EbtVoid:
1892 return "void";
1893 case EbtSampler2D:
1894 return "sampler2D";
1895 case EbtSamplerCube:
1896 return "samplerCUBE";
1897 }
1898 }
1899
1900 UNIMPLEMENTED(); // FIXME
1901 return "<unknown type>";
1902}
1903
1904TString OutputHLSL::arrayString(const TType &type)
1905{
1906 if (!type.isArray())
1907 {
1908 return "";
1909 }
1910
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001911 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001912}
1913
1914TString OutputHLSL::initializer(const TType &type)
1915{
1916 TString string;
1917
daniel@transgaming.comead23042010-04-29 03:35:36 +00001918 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001919 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001920 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001921
daniel@transgaming.comead23042010-04-29 03:35:36 +00001922 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001923 {
1924 string += ", ";
1925 }
1926 }
1927
daniel@transgaming.comead23042010-04-29 03:35:36 +00001928 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001929}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001930
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001931void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00001932{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001933 if (name == "")
1934 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001935 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001936 }
1937
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001938 TType ctorType = type;
1939 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00001940 ctorType.setPrecision(EbpHigh);
1941 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00001942
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001943 TString ctorName = type.getStruct() ? decorate(name) : name;
1944
1945 typedef std::vector<TType> ParameterArray;
1946 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001947
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001948 if (parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00001949 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001950 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
1951 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001952 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001953 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00001954 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001955 else if (type.getStruct())
1956 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001957 mStructNames.insert(decorate(name));
1958
1959 TString structure;
1960 structure += "struct " + decorate(name) + "\n"
1961 "{\n";
1962
1963 const TTypeList &fields = *type.getStruct();
1964
1965 for (unsigned int i = 0; i < fields.size(); i++)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001966 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001967 const TType &field = *fields[i].type;
1968
1969 structure += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001970 }
1971
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001972 structure += "};\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001973
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001974 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001975 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001976 mStructDeclarations.push_back(structure);
1977 }
1978
1979 for (unsigned int i = 0; i < fields.size(); i++)
1980 {
1981 ctorParameters.push_back(*fields[i].type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001982 }
1983 }
1984 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00001985
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001986 TString constructor;
1987
1988 if (ctorType.getStruct())
1989 {
1990 constructor += ctorName + " " + ctorName + "_ctor(";
1991 }
1992 else // Built-in type
1993 {
1994 constructor += typeString(ctorType) + " " + ctorName + "(";
1995 }
1996
1997 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
1998 {
1999 const TType &type = ctorParameters[parameter];
2000
2001 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2002
2003 if (parameter < ctorParameters.size() - 1)
2004 {
2005 constructor += ", ";
2006 }
2007 }
2008
2009 constructor += ")\n"
2010 "{\n";
2011
2012 if (ctorType.getStruct())
2013 {
2014 constructor += " " + ctorName + " structure = {";
2015 }
2016 else
2017 {
2018 constructor += " return " + typeString(ctorType) + "(";
2019 }
2020
2021 if (ctorType.isMatrix() && ctorParameters.size() == 1)
2022 {
2023 int dim = ctorType.getNominalSize();
2024 const TType &parameter = ctorParameters[0];
2025
2026 if (parameter.isScalar())
2027 {
2028 for (int row = 0; row < dim; row++)
2029 {
2030 for (int col = 0; col < dim; col++)
2031 {
2032 constructor += TString((row == col) ? "x0" : "0.0");
2033
2034 if (row < dim - 1 || col < dim - 1)
2035 {
2036 constructor += ", ";
2037 }
2038 }
2039 }
2040 }
2041 else if (parameter.isMatrix())
2042 {
2043 for (int row = 0; row < dim; row++)
2044 {
2045 for (int col = 0; col < dim; col++)
2046 {
2047 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2048 {
2049 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2050 }
2051 else
2052 {
2053 constructor += TString((row == col) ? "1.0" : "0.0");
2054 }
2055
2056 if (row < dim - 1 || col < dim - 1)
2057 {
2058 constructor += ", ";
2059 }
2060 }
2061 }
2062 }
2063 else UNREACHABLE();
2064 }
2065 else
2066 {
2067 int remainingComponents = ctorType.getObjectSize();
2068 int parameterIndex = 0;
2069
2070 while (remainingComponents > 0)
2071 {
2072 const TType &parameter = ctorParameters[parameterIndex];
2073 bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
2074
2075 constructor += "x" + str(parameterIndex);
2076
2077 if (parameter.isScalar())
2078 {
2079 remainingComponents -= parameter.getObjectSize();
2080 }
2081 else if (parameter.isVector())
2082 {
2083 if (remainingComponents == parameter.getObjectSize() || moreParameters)
2084 {
2085 remainingComponents -= parameter.getObjectSize();
2086 }
2087 else if (remainingComponents < parameter.getNominalSize())
2088 {
2089 switch (remainingComponents)
2090 {
2091 case 1: constructor += ".x"; break;
2092 case 2: constructor += ".xy"; break;
2093 case 3: constructor += ".xyz"; break;
2094 case 4: constructor += ".xyzw"; break;
2095 default: UNREACHABLE();
2096 }
2097
2098 remainingComponents = 0;
2099 }
2100 else UNREACHABLE();
2101 }
2102 else if (parameter.isMatrix() || parameter.getStruct())
2103 {
2104 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2105
2106 remainingComponents -= parameter.getObjectSize();
2107 }
2108 else UNREACHABLE();
2109
2110 if (moreParameters)
2111 {
2112 parameterIndex++;
2113 }
2114
2115 if (remainingComponents)
2116 {
2117 constructor += ", ";
2118 }
2119 }
2120 }
2121
2122 if (ctorType.getStruct())
2123 {
2124 constructor += "};\n"
2125 " return structure;\n"
2126 "}\n";
2127 }
2128 else
2129 {
2130 constructor += ");\n"
2131 "}\n";
2132 }
2133
daniel@transgaming.com63691862010-04-29 03:32:42 +00002134 mConstructors.insert(constructor);
2135}
2136
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002137const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2138{
2139 TInfoSinkBase &out = mBody;
2140
2141 if (type.getBasicType() == EbtStruct)
2142 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002143 out << structLookup(type.getTypeName()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002144
2145 const TTypeList *structure = type.getStruct();
2146
2147 for (size_t i = 0; i < structure->size(); i++)
2148 {
2149 const TType *fieldType = (*structure)[i].type;
2150
2151 constUnion = writeConstantUnion(*fieldType, constUnion);
2152
2153 if (i != structure->size() - 1)
2154 {
2155 out << ", ";
2156 }
2157 }
2158
2159 out << ")";
2160 }
2161 else
2162 {
2163 int size = type.getObjectSize();
2164 bool writeType = size > 1;
2165
2166 if (writeType)
2167 {
2168 out << typeString(type) << "(";
2169 }
2170
2171 for (int i = 0; i < size; i++, constUnion++)
2172 {
2173 switch (constUnion->getType())
2174 {
2175 case EbtFloat: out << constUnion->getFConst(); break;
2176 case EbtInt: out << constUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002177 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002178 default: UNREACHABLE();
2179 }
2180
2181 if (i != size - 1)
2182 {
2183 out << ", ";
2184 }
2185 }
2186
2187 if (writeType)
2188 {
2189 out << ")";
2190 }
2191 }
2192
2193 return constUnion;
2194}
2195
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002196TString OutputHLSL::scopeString(unsigned int depthLimit)
2197{
2198 TString string;
2199
2200 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2201 {
2202 string += "_" + str(i);
2203 }
2204
2205 return string;
2206}
2207
2208TString OutputHLSL::scopedStruct(const TString &typeName)
2209{
2210 if (typeName == "")
2211 {
2212 return typeName;
2213 }
2214
2215 return typeName + scopeString(mScopeDepth);
2216}
2217
2218TString OutputHLSL::structLookup(const TString &typeName)
2219{
2220 for (int depth = mScopeDepth; depth >= 0; depth--)
2221 {
2222 TString scopedName = decorate(typeName + scopeString(depth));
2223
2224 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2225 {
2226 if (*structName == scopedName)
2227 {
2228 return scopedName;
2229 }
2230 }
2231 }
2232
2233 UNREACHABLE(); // Should have found a matching constructor
2234
2235 return typeName;
2236}
2237
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002238TString OutputHLSL::decorate(const TString &string)
2239{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002240 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002241 {
2242 return "_" + string;
2243 }
2244 else
2245 {
2246 return string;
2247 }
2248}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002249}