blob: 7139fa10c00752cf5b09e90334a8e9490ae3f808 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// 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.org79fb1012012-04-26 21:07:39 +00009#include "common/angleutils.h"
alokp@chromium.org91b72322010-06-02 15:50:56 +000010#include "compiler/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "compiler/InfoSink.h"
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +000012#include "compiler/UnfoldShortCircuit.h"
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +000013#include "compiler/SearchSymbol.h"
daniel@transgaming.com89431aa2012-05-31 01:20:29 +000014#include "compiler/DetectDiscontinuity.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015
apatrick@chromium.orgbad6c2a2010-07-20 20:19:51 +000016#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000017#include <algorithm>
18
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019namespace sh
20{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000021// Integer to TString conversion
22TString str(int i)
23{
24 char buffer[20];
kbr@chromium.orgddb6e8e2012-04-25 00:48:13 +000025 snprintf(buffer, sizeof(buffer), "%d", i);
daniel@transgaming.com005c7392010-04-15 20:45:27 +000026 return buffer;
27}
28
daniel@transgaming.com950f9932010-04-13 03:26:14 +000029OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +000031 mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000032 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000033
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000034 mUsesTexture2D = false;
35 mUsesTexture2D_bias = false;
36 mUsesTexture2DProj = false;
37 mUsesTexture2DProj_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000038 mUsesTexture2DProjLod = false;
39 mUsesTexture2DLod = false;
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000040 mUsesTextureCube = false;
41 mUsesTextureCube_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000042 mUsesTextureCubeLod = false;
daniel@transgaming.coma54f5182012-05-31 01:20:16 +000043 mUsesTexture2DLod0 = false;
44 mUsesTexture2DLod0_bias = false;
45 mUsesTexture2DProjLod0 = false;
46 mUsesTexture2DProjLod0_bias = false;
47 mUsesTextureCubeLod0 = false;
48 mUsesTextureCubeLod0_bias = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000049 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000050 mUsesFragCoord = false;
51 mUsesPointCoord = false;
52 mUsesFrontFacing = false;
53 mUsesPointSize = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000054 mUsesXor = false;
55 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +000056 mUsesMod2v = false;
57 mUsesMod2f = false;
58 mUsesMod3v = false;
59 mUsesMod3f = false;
60 mUsesMod4v = false;
61 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000062 mUsesFaceforward1 = false;
63 mUsesFaceforward2 = false;
64 mUsesFaceforward3 = false;
65 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000066 mUsesEqualMat2 = false;
67 mUsesEqualMat3 = false;
68 mUsesEqualMat4 = false;
69 mUsesEqualVec2 = false;
70 mUsesEqualVec3 = false;
71 mUsesEqualVec4 = false;
72 mUsesEqualIVec2 = false;
73 mUsesEqualIVec3 = false;
74 mUsesEqualIVec4 = false;
75 mUsesEqualBVec2 = false;
76 mUsesEqualBVec3 = false;
77 mUsesEqualBVec4 = false;
daniel@transgaming.com35342dc2012-02-28 02:01:22 +000078 mUsesAtan2_1 = false;
79 mUsesAtan2_2 = false;
80 mUsesAtan2_3 = false;
81 mUsesAtan2_4 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000082
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +000083 mScopeDepth = 0;
84
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +000085 mUniqueIndex = 0;
daniel@transgaming.com89431aa2012-05-31 01:20:29 +000086
87 mContainsLoopDiscontinuity = false;
88 mOutputLod0Function = false;
daniel@transgaming.come11100c2012-05-31 01:20:32 +000089 mInsideDiscontinuousLoop = false;
daniel@transgaming.come9b3f602012-07-11 20:37:31 +000090
91 mExcessiveLoopIndex = NULL;
daniel@transgaming.com652468c2012-12-20 21:11:57 +000092
93 mUniformRegister = 0;
94 mSamplerRegister = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095}
96
daniel@transgaming.comb5875982010-04-15 20:44:53 +000097OutputHLSL::~OutputHLSL()
98{
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +000099 delete mUnfoldShortCircuit;
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000100}
101
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000102void OutputHLSL::output()
103{
daniel@transgaming.com89431aa2012-05-31 01:20:29 +0000104 mContainsLoopDiscontinuity = containsLoopDiscontinuity(mContext.treeRoot);
105
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000106 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 +0000107 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000108
alokp@chromium.org646ea1e2012-06-15 17:36:31 +0000109 mContext.infoSink().obj << mHeader.c_str();
110 mContext.infoSink().obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000111}
112
daniel@transgaming.comb5875982010-04-15 20:44:53 +0000113TInfoSinkBase &OutputHLSL::getBodyStream()
114{
115 return mBody;
116}
117
daniel@transgaming.com043da132012-12-20 21:12:22 +0000118const ActiveUniforms &OutputHLSL::getUniforms()
119{
120 return mActiveUniforms;
121}
122
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +0000123int OutputHLSL::vectorSize(const TType &type) const
124{
125 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
126 int arraySize = type.isArray() ? type.getArraySize() : 1;
127
128 return elementSize * arraySize;
129}
130
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131void OutputHLSL::header()
132{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000133 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000134 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000136 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000137 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000138 out << *structDeclaration;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000139 }
140
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000141 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000142 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000143 out << *constructor;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000144 }
145
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000146 TString uniforms;
147 TString varyings;
148 TString attributes;
149
150 for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++)
151 {
152 const TType &type = uniform->second->getType();
153 const TString &name = uniform->second->getSymbol();
154
daniel@transgaming.com652468c2012-12-20 21:11:57 +0000155 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) +
156 " : register(" + registerString(mReferencedUniforms[name]) + ");\n";
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000157 }
158
159 for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
160 {
161 const TType &type = varying->second->getType();
162 const TString &name = varying->second->getSymbol();
163
164 // Program linking depends on this exact format
165 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
166 }
167
168 for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
169 {
170 const TType &type = attribute->second->getType();
171 const TString &name = attribute->second->getSymbol();
172
173 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
174 }
175
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000176 if (shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000178 out << "// Varyings\n";
179 out << varyings;
180 out << "\n"
181 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
182
183 if (mUsesFragCoord)
184 {
185 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
186 }
187
188 if (mUsesPointCoord)
189 {
190 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
191 }
192
193 if (mUsesFrontFacing)
194 {
195 out << "static bool gl_FrontFacing = false;\n";
196 }
197
198 out << "\n";
199
200 if (mUsesFragCoord)
201 {
daniel@transgaming.com12985182012-12-20 20:56:31 +0000202 out << "uniform float4 dx_Coord;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000203 }
204
daniel@transgaming.com12985182012-12-20 20:56:31 +0000205 if (mUsesFragCoord || mUsesFrontFacing)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000206 {
daniel@transgaming.com12985182012-12-20 20:56:31 +0000207 out << "uniform float3 dx_DepthFront;\n";
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000208 }
209
210 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000212 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000213
214 if (mUsesTexture2D)
215 {
216 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
217 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000218 " return tex2D(s, t);\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000219 "}\n"
220 "\n";
221 }
222
223 if (mUsesTexture2D_bias)
224 {
225 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
226 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000227 " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000228 "}\n"
229 "\n";
230 }
231
232 if (mUsesTexture2DProj)
233 {
234 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
235 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000236 " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000237 "}\n"
238 "\n"
239 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
240 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000241 " return tex2Dproj(s, t);\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000242 "}\n"
243 "\n";
244 }
245
246 if (mUsesTexture2DProj_bias)
247 {
248 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
249 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000250 " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000251 "}\n"
252 "\n"
253 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
254 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000255 " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000256 "}\n"
257 "\n";
258 }
259
260 if (mUsesTextureCube)
261 {
262 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
263 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000264 " return texCUBE(s, t);\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000265 "}\n"
266 "\n";
267 }
268
269 if (mUsesTextureCube_bias)
270 {
271 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
272 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000273 " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000274 "}\n"
275 "\n";
276 }
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000277
278 // These *Lod0 intrinsics are not available in GL fragment shaders.
279 // They are used to sample using discontinuous texture coordinates.
280 if (mUsesTexture2DLod0)
281 {
282 out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n"
283 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000284 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000285 "}\n"
286 "\n";
287 }
288
289 if (mUsesTexture2DLod0_bias)
290 {
291 out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n"
292 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000293 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000294 "}\n"
295 "\n";
296 }
297
298 if (mUsesTexture2DProjLod0)
299 {
300 out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n"
301 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000302 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000303 "}\n"
304 "\n"
305 "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n"
306 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000307 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000308 "}\n"
309 "\n";
310 }
311
312 if (mUsesTexture2DProjLod0_bias)
313 {
314 out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n"
315 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000316 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000317 "}\n"
318 "\n"
319 "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n"
320 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000321 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000322 "}\n"
323 "\n";
324 }
325
326 if (mUsesTextureCubeLod0)
327 {
328 out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n"
329 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000330 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000331 "}\n"
332 "\n";
333 }
334
335 if (mUsesTextureCubeLod0_bias)
336 {
337 out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n"
338 "{\n"
apatrick@chromium.org9616e582012-06-22 18:27:01 +0000339 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
daniel@transgaming.coma54f5182012-05-31 01:20:16 +0000340 "}\n"
341 "\n";
342 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000344 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000346 out << "// Attributes\n";
347 out << attributes;
348 out << "\n"
349 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
350
351 if (mUsesPointSize)
352 {
353 out << "static float gl_PointSize = float(1);\n";
354 }
355
356 out << "\n"
357 "// Varyings\n";
358 out << varyings;
359 out << "\n"
360 "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000361 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000363 out << "\n";
daniel@transgaming.com15795192011-05-11 15:36:20 +0000364
365 if (mUsesTexture2D)
366 {
367 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
368 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000369 " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000370 "}\n"
371 "\n";
372 }
373
374 if (mUsesTexture2DLod)
375 {
376 out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
377 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000378 " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000379 "}\n"
380 "\n";
381 }
382
383 if (mUsesTexture2DProj)
384 {
385 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
386 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000387 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000388 "}\n"
389 "\n"
390 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
391 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000392 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000393 "}\n"
394 "\n";
395 }
396
397 if (mUsesTexture2DProjLod)
398 {
399 out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
400 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000401 " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000402 "}\n"
403 "\n"
404 "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
405 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000406 " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000407 "}\n"
408 "\n";
409 }
410
411 if (mUsesTextureCube)
412 {
413 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
414 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000415 " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000416 "}\n"
417 "\n";
418 }
419
420 if (mUsesTextureCubeLod)
421 {
422 out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
423 "{\n"
apatrick@chromium.orgdd8e4aa2012-07-12 01:33:10 +0000424 " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n"
daniel@transgaming.com15795192011-05-11 15:36:20 +0000425 "}\n"
426 "\n";
427 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 }
429
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000430 if (mUsesFragCoord)
431 {
432 out << "#define GL_USES_FRAG_COORD\n";
433 }
434
435 if (mUsesPointCoord)
436 {
437 out << "#define GL_USES_POINT_COORD\n";
438 }
439
440 if (mUsesFrontFacing)
441 {
442 out << "#define GL_USES_FRONT_FACING\n";
443 }
444
445 if (mUsesPointSize)
446 {
447 out << "#define GL_USES_POINT_SIZE\n";
448 }
449
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000450 if (mUsesDepthRange)
451 {
452 out << "struct gl_DepthRangeParameters\n"
453 "{\n"
454 " float near;\n"
455 " float far;\n"
456 " float diff;\n"
457 "};\n"
458 "\n"
daniel@transgaming.com31754962010-11-28 02:02:52 +0000459 "uniform float3 dx_DepthRange;"
460 "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000461 "\n";
462 }
463
464 if (mUsesXor)
465 {
466 out << "bool xor(bool p, bool q)\n"
467 "{\n"
468 " return (p || q) && !(p && q);\n"
469 "}\n"
470 "\n";
471 }
472
473 if (mUsesMod1)
474 {
475 out << "float mod(float x, float y)\n"
476 "{\n"
477 " return x - y * floor(x / y);\n"
478 "}\n"
479 "\n";
480 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000481
482 if (mUsesMod2v)
483 {
484 out << "float2 mod(float2 x, float2 y)\n"
485 "{\n"
486 " return x - y * floor(x / y);\n"
487 "}\n"
488 "\n";
489 }
490
491 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000492 {
493 out << "float2 mod(float2 x, float y)\n"
494 "{\n"
495 " return x - y * floor(x / y);\n"
496 "}\n"
497 "\n";
498 }
499
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000500 if (mUsesMod3v)
501 {
502 out << "float3 mod(float3 x, float3 y)\n"
503 "{\n"
504 " return x - y * floor(x / y);\n"
505 "}\n"
506 "\n";
507 }
508
509 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000510 {
511 out << "float3 mod(float3 x, float y)\n"
512 "{\n"
513 " return x - y * floor(x / y);\n"
514 "}\n"
515 "\n";
516 }
517
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000518 if (mUsesMod4v)
519 {
520 out << "float4 mod(float4 x, float4 y)\n"
521 "{\n"
522 " return x - y * floor(x / y);\n"
523 "}\n"
524 "\n";
525 }
526
527 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000528 {
529 out << "float4 mod(float4 x, float y)\n"
530 "{\n"
531 " return x - y * floor(x / y);\n"
532 "}\n"
533 "\n";
534 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000535
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000536 if (mUsesFaceforward1)
537 {
538 out << "float faceforward(float N, float I, float Nref)\n"
539 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000540 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000541 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000542 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000543 " }\n"
544 " else\n"
545 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000546 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000547 " }\n"
548 "}\n"
549 "\n";
550 }
551
552 if (mUsesFaceforward2)
553 {
554 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
555 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000556 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000557 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000558 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000559 " }\n"
560 " else\n"
561 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000562 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000563 " }\n"
564 "}\n"
565 "\n";
566 }
567
568 if (mUsesFaceforward3)
569 {
570 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
571 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000572 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000573 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000574 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000575 " }\n"
576 " else\n"
577 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000578 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000579 " }\n"
580 "}\n"
581 "\n";
582 }
583
584 if (mUsesFaceforward4)
585 {
586 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
587 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000588 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000589 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000590 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000591 " }\n"
592 " else\n"
593 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000594 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000595 " }\n"
596 "}\n"
597 "\n";
598 }
599
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000600 if (mUsesEqualMat2)
601 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000602 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000603 "{\n"
604 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
605 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
606 "}\n";
607 }
608
609 if (mUsesEqualMat3)
610 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000611 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000612 "{\n"
613 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
614 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
615 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
616 "}\n";
617 }
618
619 if (mUsesEqualMat4)
620 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000621 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000622 "{\n"
623 " 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"
624 " 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"
625 " 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"
626 " 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"
627 "}\n";
628 }
629
630 if (mUsesEqualVec2)
631 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000632 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000633 "{\n"
634 " return v.x == u.x && v.y == u.y;\n"
635 "}\n";
636 }
637
638 if (mUsesEqualVec3)
639 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000640 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000641 "{\n"
642 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
643 "}\n";
644 }
645
646 if (mUsesEqualVec4)
647 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000648 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000649 "{\n"
650 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
651 "}\n";
652 }
653
654 if (mUsesEqualIVec2)
655 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000656 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000657 "{\n"
658 " return v.x == u.x && v.y == u.y;\n"
659 "}\n";
660 }
661
662 if (mUsesEqualIVec3)
663 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000664 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000665 "{\n"
666 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
667 "}\n";
668 }
669
670 if (mUsesEqualIVec4)
671 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000672 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000673 "{\n"
674 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
675 "}\n";
676 }
677
678 if (mUsesEqualBVec2)
679 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000680 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000681 "{\n"
682 " return v.x == u.x && v.y == u.y;\n"
683 "}\n";
684 }
685
686 if (mUsesEqualBVec3)
687 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000688 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000689 "{\n"
690 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
691 "}\n";
692 }
693
694 if (mUsesEqualBVec4)
695 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000696 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000697 "{\n"
698 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
699 "}\n";
700 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000701
daniel@transgaming.com35342dc2012-02-28 02:01:22 +0000702 if (mUsesAtan2_1)
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000703 {
704 out << "float atanyx(float y, float x)\n"
705 "{\n"
706 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
707 " return atan2(y, x);\n"
708 "}\n";
709 }
daniel@transgaming.com35342dc2012-02-28 02:01:22 +0000710
711 if (mUsesAtan2_2)
712 {
713 out << "float2 atanyx(float2 y, float2 x)\n"
714 "{\n"
715 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
716 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
717 " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
718 "}\n";
719 }
720
721 if (mUsesAtan2_3)
722 {
723 out << "float3 atanyx(float3 y, float3 x)\n"
724 "{\n"
725 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
726 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
727 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
728 " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
729 "}\n";
730 }
731
732 if (mUsesAtan2_4)
733 {
734 out << "float4 atanyx(float4 y, float4 x)\n"
735 "{\n"
736 " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
737 " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
738 " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
739 " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
740 " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
741 "}\n";
742 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743}
744
745void OutputHLSL::visitSymbol(TIntermSymbol *node)
746{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000747 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000748
749 TString name = node->getSymbol();
750
751 if (name == "gl_FragColor")
752 {
753 out << "gl_Color[0]";
754 }
755 else if (name == "gl_FragData")
756 {
757 out << "gl_Color";
758 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000759 else if (name == "gl_DepthRange")
760 {
761 mUsesDepthRange = true;
762 out << name;
763 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000764 else if (name == "gl_FragCoord")
765 {
766 mUsesFragCoord = true;
767 out << name;
768 }
769 else if (name == "gl_PointCoord")
770 {
771 mUsesPointCoord = true;
772 out << name;
773 }
774 else if (name == "gl_FrontFacing")
775 {
776 mUsesFrontFacing = true;
777 out << name;
778 }
779 else if (name == "gl_PointSize")
780 {
781 mUsesPointSize = true;
782 out << name;
783 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784 else
785 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000786 TQualifier qualifier = node->getQualifier();
787
788 if (qualifier == EvqUniform)
789 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000790 mReferencedUniforms[name] = node;
apatrick@chromium.org65756022012-01-17 21:45:38 +0000791 out << decorateUniform(name, node->getType());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000792 }
793 else if (qualifier == EvqAttribute)
794 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000795 mReferencedAttributes[name] = node;
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000796 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000797 }
798 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
799 {
daniel@transgaming.com8803b852012-12-20 21:11:47 +0000800 mReferencedVaryings[name] = node;
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000801 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000802 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000803 else
804 {
805 out << decorate(name);
806 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807 }
808}
809
810bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
811{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000812 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813
814 switch (node->getOp())
815 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000816 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000817 case EOpInitialize:
818 if (visit == PreVisit)
819 {
820 // GLSL allows to write things like "float x = x;" where a new variable x is defined
821 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
822 // new variable is created before the assignment is evaluated), so we need to convert
823 // this to "float t = x, x = t;".
824
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000825 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
826 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000827
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000828 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
829 expression->traverse(&searchSymbol);
830 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000831
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000832 if (sameSymbol)
833 {
834 // Type already printed
835 out << "t" + str(mUniqueIndex) + " = ";
836 expression->traverse(this);
837 out << ", ";
838 symbolNode->traverse(this);
839 out << " = t" + str(mUniqueIndex);
840
841 mUniqueIndex++;
842 return false;
843 }
844 }
845 else if (visit == InVisit)
846 {
847 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000848 }
849 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000850 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
851 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
852 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
853 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
854 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
855 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000856 if (visit == PreVisit)
857 {
858 out << "(";
859 }
860 else if (visit == InVisit)
861 {
862 out << " = mul(";
863 node->getLeft()->traverse(this);
864 out << ", transpose(";
865 }
866 else
867 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000868 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000869 }
870 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000871 case EOpMatrixTimesMatrixAssign:
872 if (visit == PreVisit)
873 {
874 out << "(";
875 }
876 else if (visit == InVisit)
877 {
878 out << " = mul(";
879 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000880 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000881 }
882 else
883 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000884 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000885 }
886 break;
887 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000888 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
889 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000890 case EOpIndexDirectStruct:
891 if (visit == InVisit)
892 {
daniel@transgaming.com2e793f02012-04-11 19:41:35 +0000893 out << "." + decorateField(node->getType().getFieldName(), node->getLeft()->getType());
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000894
895 return false;
896 }
897 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000898 case EOpVectorSwizzle:
899 if (visit == InVisit)
900 {
901 out << ".";
902
903 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
904
905 if (swizzle)
906 {
907 TIntermSequence &sequence = swizzle->getSequence();
908
909 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
910 {
911 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
912
913 if (element)
914 {
915 int i = element->getUnionArrayPointer()[0].getIConst();
916
917 switch (i)
918 {
919 case 0: out << "x"; break;
920 case 1: out << "y"; break;
921 case 2: out << "z"; break;
922 case 3: out << "w"; break;
923 default: UNREACHABLE();
924 }
925 }
926 else UNREACHABLE();
927 }
928 }
929 else UNREACHABLE();
930
931 return false; // Fully processed
932 }
933 break;
934 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
935 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
936 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
937 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000938 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000939 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000940 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000941 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000942 if (node->getOp() == EOpEqual)
943 {
944 outputTriplet(visit, "(", " == ", ")");
945 }
946 else
947 {
948 outputTriplet(visit, "(", " != ", ")");
949 }
950 }
951 else if (node->getLeft()->getBasicType() == EbtStruct)
952 {
953 if (node->getOp() == EOpEqual)
954 {
955 out << "(";
956 }
957 else
958 {
959 out << "!(";
960 }
961
962 const TTypeList *fields = node->getLeft()->getType().getStruct();
963
964 for (size_t i = 0; i < fields->size(); i++)
965 {
966 const TType *fieldType = (*fields)[i].type;
967
968 node->getLeft()->traverse(this);
daniel@transgaming.com2e793f02012-04-11 19:41:35 +0000969 out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType()) + " == ";
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000970 node->getRight()->traverse(this);
daniel@transgaming.com2e793f02012-04-11 19:41:35 +0000971 out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType());
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000972
973 if (i < fields->size() - 1)
974 {
975 out << " && ";
976 }
977 }
978
979 out << ")";
980
981 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000982 }
983 else
984 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000985 if (node->getLeft()->isMatrix())
986 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000987 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000988 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000989 case 2: mUsesEqualMat2 = true; break;
990 case 3: mUsesEqualMat3 = true; break;
991 case 4: mUsesEqualMat4 = true; break;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000992 default: UNREACHABLE();
993 }
994 }
995 else if (node->getLeft()->isVector())
996 {
997 switch (node->getLeft()->getBasicType())
998 {
999 case EbtFloat:
alokp@chromium.org58e54292010-08-24 21:40:03 +00001000 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001001 {
1002 case 2: mUsesEqualVec2 = true; break;
1003 case 3: mUsesEqualVec3 = true; break;
1004 case 4: mUsesEqualVec4 = true; break;
1005 default: UNREACHABLE();
1006 }
1007 break;
1008 case EbtInt:
alokp@chromium.org58e54292010-08-24 21:40:03 +00001009 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001010 {
1011 case 2: mUsesEqualIVec2 = true; break;
1012 case 3: mUsesEqualIVec3 = true; break;
1013 case 4: mUsesEqualIVec4 = true; break;
1014 default: UNREACHABLE();
1015 }
1016 break;
1017 case EbtBool:
alokp@chromium.org58e54292010-08-24 21:40:03 +00001018 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001019 {
1020 case 2: mUsesEqualBVec2 = true; break;
1021 case 3: mUsesEqualBVec3 = true; break;
1022 case 4: mUsesEqualBVec4 = true; break;
1023 default: UNREACHABLE();
1024 }
1025 break;
1026 default: UNREACHABLE();
1027 }
1028 }
1029 else UNREACHABLE();
1030
1031 if (node->getOp() == EOpEqual)
1032 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001033 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001034 }
1035 else
1036 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001037 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001038 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001039 }
1040 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001041 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1042 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1043 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1044 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1045 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001046 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001047 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1048 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001049 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001050 case EOpLogicalOr:
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00001051 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001052 return false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001053 case EOpLogicalXor:
1054 mUsesXor = true;
1055 outputTriplet(visit, "xor(", ", ", ")");
1056 break;
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001057 case EOpLogicalAnd:
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00001058 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
daniel@transgaming.com8915eba2012-04-28 00:34:44 +00001059 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001060 default: UNREACHABLE();
1061 }
1062
1063 return true;
1064}
1065
1066bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1067{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068 switch (node->getOp())
1069 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001070 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
1071 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1072 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1073 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1074 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1075 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1076 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001077 case EOpConvIntToBool:
1078 case EOpConvFloatToBool:
1079 switch (node->getOperand()->getType().getNominalSize())
1080 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001081 case 1: outputTriplet(visit, "bool(", "", ")"); break;
1082 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
1083 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
1084 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 default: UNREACHABLE();
1086 }
1087 break;
1088 case EOpConvBoolToFloat:
1089 case EOpConvIntToFloat:
1090 switch (node->getOperand()->getType().getNominalSize())
1091 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001092 case 1: outputTriplet(visit, "float(", "", ")"); break;
1093 case 2: outputTriplet(visit, "float2(", "", ")"); break;
1094 case 3: outputTriplet(visit, "float3(", "", ")"); break;
1095 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 default: UNREACHABLE();
1097 }
1098 break;
1099 case EOpConvFloatToInt:
1100 case EOpConvBoolToInt:
1101 switch (node->getOperand()->getType().getNominalSize())
1102 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001103 case 1: outputTriplet(visit, "int(", "", ")"); break;
1104 case 2: outputTriplet(visit, "int2(", "", ")"); break;
1105 case 3: outputTriplet(visit, "int3(", "", ")"); break;
1106 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001107 default: UNREACHABLE();
1108 }
1109 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001110 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1111 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1112 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1113 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1114 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1115 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1116 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1117 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
1118 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1119 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1120 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1121 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1122 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1123 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1124 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1125 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1126 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
1127 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1128 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
1129 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1130 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001131 case EOpDFdx:
1132 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1133 {
1134 outputTriplet(visit, "(", "", ", 0.0)");
1135 }
1136 else
1137 {
1138 outputTriplet(visit, "ddx(", "", ")");
1139 }
1140 break;
1141 case EOpDFdy:
1142 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1143 {
1144 outputTriplet(visit, "(", "", ", 0.0)");
1145 }
1146 else
1147 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001148 outputTriplet(visit, "ddy(", "", ")");
daniel@transgaming.comddbb45d2012-05-31 01:21:41 +00001149 }
1150 break;
1151 case EOpFwidth:
1152 if(mInsideDiscontinuousLoop || mOutputLod0Function)
1153 {
1154 outputTriplet(visit, "(", "", ", 0.0)");
1155 }
1156 else
1157 {
1158 outputTriplet(visit, "fwidth(", "", ")");
1159 }
1160 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001161 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1162 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001163 default: UNREACHABLE();
1164 }
1165
1166 return true;
1167}
1168
1169bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1170{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001171 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001172
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001173 switch (node->getOp())
1174 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001175 case EOpSequence:
1176 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001177 if (mInsideFunction)
1178 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001179 outputLineDirective(node->getLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001180 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001181
1182 mScopeDepth++;
1183
1184 if (mScopeBracket.size() < mScopeDepth)
1185 {
1186 mScopeBracket.push_back(0); // New scope level
1187 }
1188 else
1189 {
1190 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
1191 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001192 }
1193
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001194 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1195 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001196 outputLineDirective((*sit)->getLine());
1197
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001198 traverseStatements(*sit);
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001199
1200 out << ";\n";
1201 }
1202
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001203 if (mInsideFunction)
1204 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001205 outputLineDirective(node->getEndLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001206 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001207
1208 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001209 }
1210
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001211 return false;
1212 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001213 case EOpDeclaration:
1214 if (visit == PreVisit)
1215 {
1216 TIntermSequence &sequence = node->getSequence();
1217 TIntermTyped *variable = sequence[0]->getAsTyped();
1218 bool visit = true;
1219
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001220 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001221 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001222 if (variable->getType().getStruct())
1223 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001224 addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001225 }
1226
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001227 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001229 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001230 {
1231 out << "static ";
1232 }
1233
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001234 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001235
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001236 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001237 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001238 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001239
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001240 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001241 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001242 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001243 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001244 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001245 }
1246 else
1247 {
1248 (*sit)->traverse(this);
1249 }
1250
1251 if (visit && this->inVisit)
1252 {
1253 if (*sit != sequence.back())
1254 {
1255 visit = this->visitAggregate(InVisit, node);
1256 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001257 }
1258 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001259
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001260 if (visit && this->postVisit)
1261 {
1262 this->visitAggregate(PostVisit, node);
1263 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001265 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1266 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001267 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001268 }
1269 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001270 }
1271
1272 return false;
1273 }
1274 else if (visit == InVisit)
1275 {
1276 out << ", ";
1277 }
1278 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001279 case EOpPrototype:
1280 if (visit == PreVisit)
1281 {
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00001282 out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001283
1284 TIntermSequence &arguments = node->getSequence();
1285
1286 for (unsigned int i = 0; i < arguments.size(); i++)
1287 {
1288 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1289
1290 if (symbol)
1291 {
1292 out << argumentString(symbol);
1293
1294 if (i < arguments.size() - 1)
1295 {
1296 out << ", ";
1297 }
1298 }
1299 else UNREACHABLE();
1300 }
1301
1302 out << ");\n";
1303
daniel@transgaming.com0e5bb402012-10-17 18:24:53 +00001304 // Also prototype the Lod0 variant if needed
1305 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
1306 {
1307 mOutputLod0Function = true;
1308 node->traverse(this);
1309 mOutputLod0Function = false;
1310 }
1311
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001312 return false;
1313 }
1314 break;
daniel@transgaming.comed2180d2012-03-26 17:08:54 +00001315 case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 case EOpFunction:
1317 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001318 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001319
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001320 out << typeString(node->getType()) << " ";
1321
1322 if (name == "main")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001323 {
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001324 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001325 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001326 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001327 {
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00001328 out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001329 }
daniel@transgaming.com63691862010-04-29 03:32:42 +00001330
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001331 TIntermSequence &sequence = node->getSequence();
1332 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1333
1334 for (unsigned int i = 0; i < arguments.size(); i++)
1335 {
1336 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1337
1338 if (symbol)
1339 {
1340 if (symbol->getType().getStruct())
1341 {
1342 addConstructor(symbol->getType(), scopedStruct(symbol->getType().getTypeName()), NULL);
1343 }
1344
1345 out << argumentString(symbol);
1346
1347 if (i < arguments.size() - 1)
1348 {
1349 out << ", ";
1350 }
1351 }
1352 else UNREACHABLE();
1353 }
1354
1355 out << ")\n"
1356 "{\n";
1357
1358 if (sequence.size() > 1)
1359 {
1360 mInsideFunction = true;
1361 sequence[1]->traverse(this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001362 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001363 }
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001364
1365 out << "}\n";
1366
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00001367 if (mContainsLoopDiscontinuity && !mOutputLod0Function)
1368 {
daniel@transgaming.comecdf44a2012-06-01 01:45:15 +00001369 if (name != "main")
daniel@transgaming.com89431aa2012-05-31 01:20:29 +00001370 {
1371 mOutputLod0Function = true;
1372 node->traverse(this);
1373 mOutputLod0Function = false;
1374 }
1375 }
1376
daniel@transgaming.com0e9704b2012-05-31 01:20:13 +00001377 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001378 }
1379 break;
1380 case EOpFunctionCall:
1381 {
1382 if (visit == PreVisit)
1383 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001384 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001385 bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001386
1387 if (node->isUserDefined())
1388 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001389 out << decorate(name) << (lod0 ? "Lod0(" : "(");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001390 }
1391 else
1392 {
1393 if (name == "texture2D")
1394 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001395 if (!lod0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001396 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001397 if (node->getSequence().size() == 2)
1398 {
1399 mUsesTexture2D = true;
1400 }
1401 else if (node->getSequence().size() == 3)
1402 {
1403 mUsesTexture2D_bias = true;
1404 }
1405 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001406
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001407 out << "gl_texture2D(";
1408 }
1409 else
1410 {
1411 if (node->getSequence().size() == 2)
1412 {
1413 mUsesTexture2DLod0 = true;
1414 }
1415 else if (node->getSequence().size() == 3)
1416 {
1417 mUsesTexture2DLod0_bias = true;
1418 }
1419 else UNREACHABLE();
1420
1421 out << "gl_texture2DLod0(";
1422 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001423 }
1424 else if (name == "texture2DProj")
1425 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001426 if (!lod0)
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001427 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001428 if (node->getSequence().size() == 2)
1429 {
1430 mUsesTexture2DProj = true;
1431 }
1432 else if (node->getSequence().size() == 3)
1433 {
1434 mUsesTexture2DProj_bias = true;
1435 }
1436 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001437
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001438 out << "gl_texture2DProj(";
1439 }
1440 else
1441 {
1442 if (node->getSequence().size() == 2)
1443 {
1444 mUsesTexture2DProjLod0 = true;
1445 }
1446 else if (node->getSequence().size() == 3)
1447 {
1448 mUsesTexture2DProjLod0_bias = true;
1449 }
1450 else UNREACHABLE();
1451
1452 out << "gl_texture2DProjLod0(";
1453 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001454 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001455 else if (name == "textureCube")
1456 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001457 if (!lod0)
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001458 {
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001459 if (node->getSequence().size() == 2)
1460 {
1461 mUsesTextureCube = true;
1462 }
1463 else if (node->getSequence().size() == 3)
1464 {
1465 mUsesTextureCube_bias = true;
1466 }
1467 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001468
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001469 out << "gl_textureCube(";
1470 }
1471 else
1472 {
1473 if (node->getSequence().size() == 2)
1474 {
1475 mUsesTextureCubeLod0 = true;
1476 }
1477 else if (node->getSequence().size() == 3)
1478 {
1479 mUsesTextureCubeLod0_bias = true;
1480 }
1481 else UNREACHABLE();
1482
1483 out << "gl_textureCubeLod0(";
1484 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001485 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001486 else if (name == "texture2DLod")
1487 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001488 if (node->getSequence().size() == 3)
1489 {
1490 mUsesTexture2DLod = true;
1491 }
1492 else UNREACHABLE();
1493
1494 out << "gl_texture2DLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495 }
1496 else if (name == "texture2DProjLod")
1497 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001498 if (node->getSequence().size() == 3)
1499 {
1500 mUsesTexture2DProjLod = true;
1501 }
1502 else UNREACHABLE();
1503
1504 out << "gl_texture2DProjLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001505 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001506 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001507 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001508 if (node->getSequence().size() == 3)
1509 {
1510 mUsesTextureCubeLod = true;
1511 }
1512 else UNREACHABLE();
1513
1514 out << "gl_textureCubeLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001515 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001516 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001517 }
1518 }
1519 else if (visit == InVisit)
1520 {
1521 out << ", ";
1522 }
1523 else
1524 {
1525 out << ")";
1526 }
1527 }
1528 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001529 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001530 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001531 addConstructor(node->getType(), "vec1", &node->getSequence());
1532 outputTriplet(visit, "vec1(", "", ")");
1533 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001534 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001535 addConstructor(node->getType(), "vec2", &node->getSequence());
1536 outputTriplet(visit, "vec2(", ", ", ")");
1537 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001538 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001539 addConstructor(node->getType(), "vec3", &node->getSequence());
1540 outputTriplet(visit, "vec3(", ", ", ")");
1541 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001542 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001543 addConstructor(node->getType(), "vec4", &node->getSequence());
1544 outputTriplet(visit, "vec4(", ", ", ")");
1545 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001546 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001547 addConstructor(node->getType(), "bvec1", &node->getSequence());
1548 outputTriplet(visit, "bvec1(", "", ")");
1549 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001550 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001551 addConstructor(node->getType(), "bvec2", &node->getSequence());
1552 outputTriplet(visit, "bvec2(", ", ", ")");
1553 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001554 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001555 addConstructor(node->getType(), "bvec3", &node->getSequence());
1556 outputTriplet(visit, "bvec3(", ", ", ")");
1557 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001558 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001559 addConstructor(node->getType(), "bvec4", &node->getSequence());
1560 outputTriplet(visit, "bvec4(", ", ", ")");
1561 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001562 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001563 addConstructor(node->getType(), "ivec1", &node->getSequence());
1564 outputTriplet(visit, "ivec1(", "", ")");
1565 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001566 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001567 addConstructor(node->getType(), "ivec2", &node->getSequence());
1568 outputTriplet(visit, "ivec2(", ", ", ")");
1569 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001570 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001571 addConstructor(node->getType(), "ivec3", &node->getSequence());
1572 outputTriplet(visit, "ivec3(", ", ", ")");
1573 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001574 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001575 addConstructor(node->getType(), "ivec4", &node->getSequence());
1576 outputTriplet(visit, "ivec4(", ", ", ")");
1577 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001578 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001579 addConstructor(node->getType(), "mat2", &node->getSequence());
1580 outputTriplet(visit, "mat2(", ", ", ")");
1581 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001582 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001583 addConstructor(node->getType(), "mat3", &node->getSequence());
1584 outputTriplet(visit, "mat3(", ", ", ")");
1585 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001586 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001587 addConstructor(node->getType(), "mat4", &node->getSequence());
1588 outputTriplet(visit, "mat4(", ", ", ")");
1589 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001590 case EOpConstructStruct:
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001591 addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1592 outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001593 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001594 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1595 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1596 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1597 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1598 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1599 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001600 case EOpMod:
1601 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001602 // We need to look at the number of components in both arguments
1603 switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
1604 + node->getSequence()[1]->getAsTyped()->getNominalSize())
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001605 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001606 case 11: mUsesMod1 = true; break;
1607 case 22: mUsesMod2v = true; break;
1608 case 21: mUsesMod2f = true; break;
1609 case 33: mUsesMod3v = true; break;
1610 case 31: mUsesMod3f = true; break;
1611 case 44: mUsesMod4v = true; break;
1612 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001613 default: UNREACHABLE();
1614 }
1615
1616 outputTriplet(visit, "mod(", ", ", ")");
1617 }
1618 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001619 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001620 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001621 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
daniel@transgaming.com35342dc2012-02-28 02:01:22 +00001622 switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
1623 {
1624 case 1: mUsesAtan2_1 = true; break;
1625 case 2: mUsesAtan2_2 = true; break;
1626 case 3: mUsesAtan2_3 = true; break;
1627 case 4: mUsesAtan2_4 = true; break;
1628 default: UNREACHABLE();
1629 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001630 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001631 break;
1632 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1633 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1634 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1635 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1636 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1637 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1638 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1639 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1640 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001641 case EOpFaceForward:
1642 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001643 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001644 {
1645 case 1: mUsesFaceforward1 = true; break;
1646 case 2: mUsesFaceforward2 = true; break;
1647 case 3: mUsesFaceforward3 = true; break;
1648 case 4: mUsesFaceforward4 = true; break;
1649 default: UNREACHABLE();
1650 }
1651
1652 outputTriplet(visit, "faceforward(", ", ", ")");
1653 }
1654 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1656 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1657 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001658 default: UNREACHABLE();
1659 }
1660
1661 return true;
1662}
1663
1664bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1665{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001666 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001668 if (node->usesTernaryOperator())
1669 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00001670 out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001671 }
1672 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00001674 mUnfoldShortCircuit->traverse(node->getCondition());
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001675
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001676 out << "if(";
1677
1678 node->getCondition()->traverse(this);
1679
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001680 out << ")\n";
1681
1682 outputLineDirective(node->getLine());
1683 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001684
daniel@transgaming.combb885322010-04-15 20:45:24 +00001685 if (node->getTrueBlock())
1686 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001687 traverseStatements(node->getTrueBlock());
daniel@transgaming.combb885322010-04-15 20:45:24 +00001688 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001689
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001690 outputLineDirective(node->getLine());
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001691 out << ";\n}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001692
1693 if (node->getFalseBlock())
1694 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001695 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001696
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001697 outputLineDirective(node->getFalseBlock()->getLine());
1698 out << "{\n";
1699
1700 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001701 traverseStatements(node->getFalseBlock());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001702
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001703 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001704 out << ";\n}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001705 }
1706 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001707
1708 return false;
1709}
1710
1711void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1712{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001713 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001714}
1715
1716bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1717{
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001718 bool wasDiscontinuous = mInsideDiscontinuousLoop;
1719
1720 if (!mInsideDiscontinuousLoop)
1721 {
1722 mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
1723 }
1724
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001725 if (handleExcessiveLoop(node))
1726 {
1727 return false;
1728 }
1729
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001730 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001731
alokp@chromium.org52813552010-11-16 18:36:09 +00001732 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001733 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00001734 out << "{do\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001735
1736 outputLineDirective(node->getLine());
1737 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001738 }
1739 else
1740 {
daniel@transgaming.com2a073de2012-03-09 21:56:43 +00001741 out << "{for(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001742
1743 if (node->getInit())
1744 {
1745 node->getInit()->traverse(this);
1746 }
1747
1748 out << "; ";
1749
alokp@chromium.org52813552010-11-16 18:36:09 +00001750 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001751 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001752 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001753 }
1754
1755 out << "; ";
1756
alokp@chromium.org52813552010-11-16 18:36:09 +00001757 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001759 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760 }
1761
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001762 out << ")\n";
1763
1764 outputLineDirective(node->getLine());
1765 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001766 }
1767
1768 if (node->getBody())
1769 {
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001770 traverseStatements(node->getBody());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001771 }
1772
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001773 outputLineDirective(node->getLine());
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00001774 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001775
alokp@chromium.org52813552010-11-16 18:36:09 +00001776 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001777 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001778 outputLineDirective(node->getCondition()->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001779 out << "while(\n";
1780
alokp@chromium.org52813552010-11-16 18:36:09 +00001781 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001782
daniel@transgaming.com73536982012-03-21 20:45:49 +00001783 out << ");";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001784 }
1785
daniel@transgaming.com73536982012-03-21 20:45:49 +00001786 out << "}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001787
daniel@transgaming.come11100c2012-05-31 01:20:32 +00001788 mInsideDiscontinuousLoop = wasDiscontinuous;
1789
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001790 return false;
1791}
1792
1793bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1794{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001795 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001796
1797 switch (node->getFlowOp())
1798 {
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00001799 case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00001800 case EOpBreak:
1801 if (visit == PreVisit)
1802 {
1803 if (mExcessiveLoopIndex)
1804 {
1805 out << "{Break";
1806 mExcessiveLoopIndex->traverse(this);
1807 out << " = true; break;}\n";
1808 }
1809 else
1810 {
1811 out << "break;\n";
1812 }
1813 }
1814 break;
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00001815 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001816 case EOpReturn:
1817 if (visit == PreVisit)
1818 {
1819 if (node->getExpression())
1820 {
1821 out << "return ";
1822 }
1823 else
1824 {
1825 out << "return;\n";
1826 }
1827 }
1828 else if (visit == PostVisit)
1829 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001830 if (node->getExpression())
1831 {
1832 out << ";\n";
1833 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001834 }
1835 break;
1836 default: UNREACHABLE();
1837 }
1838
1839 return true;
1840}
1841
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001842void OutputHLSL::traverseStatements(TIntermNode *node)
1843{
1844 if (isSingleStatement(node))
1845 {
daniel@transgaming.comf8f8f362012-04-28 00:35:00 +00001846 mUnfoldShortCircuit->traverse(node);
daniel@transgaming.com44fffee2012-04-28 00:34:20 +00001847 }
1848
1849 node->traverse(this);
1850}
1851
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001852bool OutputHLSL::isSingleStatement(TIntermNode *node)
1853{
1854 TIntermAggregate *aggregate = node->getAsAggregate();
1855
1856 if (aggregate)
1857 {
1858 if (aggregate->getOp() == EOpSequence)
1859 {
1860 return false;
1861 }
1862 else
1863 {
1864 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1865 {
1866 if (!isSingleStatement(*sit))
1867 {
1868 return false;
1869 }
1870 }
1871
1872 return true;
1873 }
1874 }
1875
1876 return true;
1877}
1878
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00001879// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
1880// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001881bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1882{
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00001883 const int MAX_LOOP_ITERATIONS = 254;
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001884 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001885
1886 // Parse loops of the form:
1887 // for(int index = initial; index [comparator] limit; index += increment)
1888 TIntermSymbol *index = NULL;
1889 TOperator comparator = EOpNull;
1890 int initial = 0;
1891 int limit = 0;
1892 int increment = 0;
1893
1894 // Parse index name and intial value
1895 if (node->getInit())
1896 {
1897 TIntermAggregate *init = node->getInit()->getAsAggregate();
1898
1899 if (init)
1900 {
1901 TIntermSequence &sequence = init->getSequence();
1902 TIntermTyped *variable = sequence[0]->getAsTyped();
1903
1904 if (variable && variable->getQualifier() == EvqTemporary)
1905 {
1906 TIntermBinary *assign = variable->getAsBinaryNode();
1907
1908 if (assign->getOp() == EOpInitialize)
1909 {
1910 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1911 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1912
1913 if (symbol && constant)
1914 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001915 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001916 {
1917 index = symbol;
1918 initial = constant->getUnionArrayPointer()[0].getIConst();
1919 }
1920 }
1921 }
1922 }
1923 }
1924 }
1925
1926 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00001927 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001928 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001929 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001930
1931 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1932 {
1933 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1934
1935 if (constant)
1936 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001937 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001938 {
1939 comparator = test->getOp();
1940 limit = constant->getUnionArrayPointer()[0].getIConst();
1941 }
1942 }
1943 }
1944 }
1945
1946 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00001947 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001948 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001949 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
1950 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001951
1952 if (binaryTerminal)
1953 {
1954 TOperator op = binaryTerminal->getOp();
1955 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1956
1957 if (constant)
1958 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001959 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001960 {
1961 int value = constant->getUnionArrayPointer()[0].getIConst();
1962
1963 switch (op)
1964 {
1965 case EOpAddAssign: increment = value; break;
1966 case EOpSubAssign: increment = -value; break;
1967 default: UNIMPLEMENTED();
1968 }
1969 }
1970 }
1971 }
1972 else if (unaryTerminal)
1973 {
1974 TOperator op = unaryTerminal->getOp();
1975
1976 switch (op)
1977 {
1978 case EOpPostIncrement: increment = 1; break;
1979 case EOpPostDecrement: increment = -1; break;
1980 case EOpPreIncrement: increment = 1; break;
1981 case EOpPreDecrement: increment = -1; break;
1982 default: UNIMPLEMENTED();
1983 }
1984 }
1985 }
1986
1987 if (index != NULL && comparator != EOpNull && increment != 0)
1988 {
1989 if (comparator == EOpLessThanEqual)
1990 {
1991 comparator = EOpLessThan;
1992 limit += 1;
1993 }
1994
1995 if (comparator == EOpLessThan)
1996 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001997 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001998
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00001999 if (iterations <= MAX_LOOP_ITERATIONS)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002000 {
2001 return false; // Not an excessive loop
2002 }
2003
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002004 TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
2005 mExcessiveLoopIndex = index;
2006
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002007 out << "{int ";
2008 index->traverse(this);
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002009 out << ";\n"
2010 "bool Break";
2011 index->traverse(this);
2012 out << " = false;\n";
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002013
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002014 bool firstLoopFragment = true;
2015
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002016 while (iterations > 0)
2017 {
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002018 int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002019
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002020 if (!firstLoopFragment)
2021 {
2022 out << "if(!Break";
2023 index->traverse(this);
2024 out << ") {\n";
2025 }
daniel@transgaming.com2fe20a82012-07-11 20:37:41 +00002026
2027 if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
2028 {
2029 mExcessiveLoopIndex = NULL; // Stops setting the Break flag
2030 }
daniel@transgaming.com8c77f852012-07-11 20:37:35 +00002031
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002032 // for(int index = initial; index < clampedLimit; index += increment)
2033
daniel@transgaming.com0933b0c2012-07-11 20:37:28 +00002034 out << "for(";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002035 index->traverse(this);
2036 out << " = ";
2037 out << initial;
2038
2039 out << "; ";
2040 index->traverse(this);
2041 out << " < ";
2042 out << clampedLimit;
2043
2044 out << "; ";
2045 index->traverse(this);
2046 out << " += ";
2047 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002048 out << ")\n";
2049
2050 outputLineDirective(node->getLine());
2051 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002052
2053 if (node->getBody())
2054 {
2055 node->getBody()->traverse(this);
2056 }
2057
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002058 outputLineDirective(node->getLine());
daniel@transgaming.com5b60f5e2012-07-11 20:37:38 +00002059 out << ";}\n";
2060
2061 if (!firstLoopFragment)
2062 {
2063 out << "}\n";
2064 }
2065
2066 firstLoopFragment = false;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002067
daniel@transgaming.com06eb0d42012-05-31 01:17:14 +00002068 initial += MAX_LOOP_ITERATIONS * increment;
2069 iterations -= MAX_LOOP_ITERATIONS;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002070 }
daniel@transgaming.comc264de42012-07-11 20:37:25 +00002071
2072 out << "}";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002073
daniel@transgaming.come9b3f602012-07-11 20:37:31 +00002074 mExcessiveLoopIndex = restoreIndex;
2075
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00002076 return true;
2077 }
2078 else UNIMPLEMENTED();
2079 }
2080
2081 return false; // Not handled as an excessive loop
2082}
2083
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002084void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002085{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00002086 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002087
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002088 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002089 {
2090 out << preString;
2091 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002092 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002093 {
2094 out << inString;
2095 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002096 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002097 {
2098 out << postString;
2099 }
2100}
2101
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002102void OutputHLSL::outputLineDirective(int line)
2103{
2104 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
2105 {
baustin@google.com8ab69842011-06-02 21:53:45 +00002106 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00002107 mBody << "#line " << line;
2108
2109 if (mContext.sourcePath)
2110 {
2111 mBody << " \"" << mContext.sourcePath << "\"";
2112 }
2113
2114 mBody << "\n";
2115 }
2116}
2117
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002118TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
2119{
2120 TQualifier qualifier = symbol->getQualifier();
2121 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002122 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002123
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002124 if (name.empty()) // HLSL demands named arguments, also for prototypes
2125 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00002126 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002127 }
2128 else
2129 {
2130 name = decorate(name);
2131 }
2132
2133 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00002134}
2135
2136TString OutputHLSL::qualifierString(TQualifier qualifier)
2137{
2138 switch(qualifier)
2139 {
2140 case EvqIn: return "in";
2141 case EvqOut: return "out";
2142 case EvqInOut: return "inout";
2143 case EvqConstReadOnly: return "const";
2144 default: UNREACHABLE();
2145 }
2146
2147 return "";
2148}
2149
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002150TString OutputHLSL::typeString(const TType &type)
2151{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002152 if (type.getBasicType() == EbtStruct)
2153 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002154 if (type.getTypeName() != "")
2155 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002156 return structLookup(type.getTypeName());
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002157 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00002158 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002159 {
2160 const TTypeList &fields = *type.getStruct();
2161
2162 TString string = "struct\n"
2163 "{\n";
2164
2165 for (unsigned int i = 0; i < fields.size(); i++)
2166 {
2167 const TType &field = *fields[i].type;
2168
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002169 string += " " + typeString(field) + " " + decorate(field.getFieldName()) + arrayString(field) + ";\n";
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002170 }
2171
2172 string += "} ";
2173
2174 return string;
2175 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00002176 }
2177 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002178 {
2179 switch (type.getNominalSize())
2180 {
2181 case 2: return "float2x2";
2182 case 3: return "float3x3";
2183 case 4: return "float4x4";
2184 }
2185 }
2186 else
2187 {
2188 switch (type.getBasicType())
2189 {
2190 case EbtFloat:
2191 switch (type.getNominalSize())
2192 {
2193 case 1: return "float";
2194 case 2: return "float2";
2195 case 3: return "float3";
2196 case 4: return "float4";
2197 }
2198 case EbtInt:
2199 switch (type.getNominalSize())
2200 {
2201 case 1: return "int";
2202 case 2: return "int2";
2203 case 3: return "int3";
2204 case 4: return "int4";
2205 }
2206 case EbtBool:
2207 switch (type.getNominalSize())
2208 {
2209 case 1: return "bool";
2210 case 2: return "bool2";
2211 case 3: return "bool3";
2212 case 4: return "bool4";
2213 }
2214 case EbtVoid:
2215 return "void";
2216 case EbtSampler2D:
2217 return "sampler2D";
2218 case EbtSamplerCube:
2219 return "samplerCUBE";
apatrick@chromium.org65756022012-01-17 21:45:38 +00002220 case EbtSamplerExternalOES:
2221 return "sampler2D";
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +00002222 default:
2223 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002224 }
2225 }
2226
2227 UNIMPLEMENTED(); // FIXME
2228 return "<unknown type>";
2229}
2230
2231TString OutputHLSL::arrayString(const TType &type)
2232{
2233 if (!type.isArray())
2234 {
2235 return "";
2236 }
2237
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002238 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002239}
2240
2241TString OutputHLSL::initializer(const TType &type)
2242{
2243 TString string;
2244
daniel@transgaming.comead23042010-04-29 03:35:36 +00002245 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002246 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002247 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002248
daniel@transgaming.comead23042010-04-29 03:35:36 +00002249 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002250 {
2251 string += ", ";
2252 }
2253 }
2254
daniel@transgaming.comead23042010-04-29 03:35:36 +00002255 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002256}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002257
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002258void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00002259{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002260 if (name == "")
2261 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00002262 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002263 }
2264
daniel@transgaming.com43eecdc2012-03-20 20:10:33 +00002265 if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
2266 {
2267 return; // Already added
2268 }
2269
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002270 TType ctorType = type;
2271 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00002272 ctorType.setPrecision(EbpHigh);
2273 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00002274
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002275 TString ctorName = type.getStruct() ? decorate(name) : name;
2276
2277 typedef std::vector<TType> ParameterArray;
2278 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002279
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002280 if (type.getStruct())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002281 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002282 mStructNames.insert(decorate(name));
2283
2284 TString structure;
2285 structure += "struct " + decorate(name) + "\n"
2286 "{\n";
2287
2288 const TTypeList &fields = *type.getStruct();
2289
2290 for (unsigned int i = 0; i < fields.size(); i++)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002291 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002292 const TType &field = *fields[i].type;
2293
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002294 structure += " " + typeString(field) + " " + decorateField(field.getFieldName(), type) + arrayString(field) + ";\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002295 }
2296
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002297 structure += "};\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002298
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002299 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002300 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002301 mStructDeclarations.push_back(structure);
2302 }
2303
2304 for (unsigned int i = 0; i < fields.size(); i++)
2305 {
2306 ctorParameters.push_back(*fields[i].type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002307 }
2308 }
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002309 else if (parameters)
2310 {
2311 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2312 {
2313 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
2314 }
2315 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002316 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00002317
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002318 TString constructor;
2319
2320 if (ctorType.getStruct())
2321 {
2322 constructor += ctorName + " " + ctorName + "_ctor(";
2323 }
2324 else // Built-in type
2325 {
2326 constructor += typeString(ctorType) + " " + ctorName + "(";
2327 }
2328
2329 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
2330 {
2331 const TType &type = ctorParameters[parameter];
2332
2333 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2334
2335 if (parameter < ctorParameters.size() - 1)
2336 {
2337 constructor += ", ";
2338 }
2339 }
2340
2341 constructor += ")\n"
2342 "{\n";
2343
2344 if (ctorType.getStruct())
2345 {
2346 constructor += " " + ctorName + " structure = {";
2347 }
2348 else
2349 {
2350 constructor += " return " + typeString(ctorType) + "(";
2351 }
2352
2353 if (ctorType.isMatrix() && ctorParameters.size() == 1)
2354 {
2355 int dim = ctorType.getNominalSize();
2356 const TType &parameter = ctorParameters[0];
2357
2358 if (parameter.isScalar())
2359 {
2360 for (int row = 0; row < dim; row++)
2361 {
2362 for (int col = 0; col < dim; col++)
2363 {
2364 constructor += TString((row == col) ? "x0" : "0.0");
2365
2366 if (row < dim - 1 || col < dim - 1)
2367 {
2368 constructor += ", ";
2369 }
2370 }
2371 }
2372 }
2373 else if (parameter.isMatrix())
2374 {
2375 for (int row = 0; row < dim; row++)
2376 {
2377 for (int col = 0; col < dim; col++)
2378 {
2379 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2380 {
2381 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2382 }
2383 else
2384 {
2385 constructor += TString((row == col) ? "1.0" : "0.0");
2386 }
2387
2388 if (row < dim - 1 || col < dim - 1)
2389 {
2390 constructor += ", ";
2391 }
2392 }
2393 }
2394 }
2395 else UNREACHABLE();
2396 }
2397 else
2398 {
2399 int remainingComponents = ctorType.getObjectSize();
2400 int parameterIndex = 0;
2401
2402 while (remainingComponents > 0)
2403 {
2404 const TType &parameter = ctorParameters[parameterIndex];
2405 bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
2406
2407 constructor += "x" + str(parameterIndex);
2408
2409 if (parameter.isScalar())
2410 {
2411 remainingComponents -= parameter.getObjectSize();
2412 }
2413 else if (parameter.isVector())
2414 {
2415 if (remainingComponents == parameter.getObjectSize() || moreParameters)
2416 {
2417 remainingComponents -= parameter.getObjectSize();
2418 }
2419 else if (remainingComponents < parameter.getNominalSize())
2420 {
2421 switch (remainingComponents)
2422 {
2423 case 1: constructor += ".x"; break;
2424 case 2: constructor += ".xy"; break;
2425 case 3: constructor += ".xyz"; break;
2426 case 4: constructor += ".xyzw"; break;
2427 default: UNREACHABLE();
2428 }
2429
2430 remainingComponents = 0;
2431 }
2432 else UNREACHABLE();
2433 }
2434 else if (parameter.isMatrix() || parameter.getStruct())
2435 {
2436 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2437
2438 remainingComponents -= parameter.getObjectSize();
2439 }
2440 else UNREACHABLE();
2441
2442 if (moreParameters)
2443 {
2444 parameterIndex++;
2445 }
2446
2447 if (remainingComponents)
2448 {
2449 constructor += ", ";
2450 }
2451 }
2452 }
2453
2454 if (ctorType.getStruct())
2455 {
2456 constructor += "};\n"
2457 " return structure;\n"
2458 "}\n";
2459 }
2460 else
2461 {
2462 constructor += ");\n"
2463 "}\n";
2464 }
2465
daniel@transgaming.com63691862010-04-29 03:32:42 +00002466 mConstructors.insert(constructor);
2467}
2468
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002469const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2470{
2471 TInfoSinkBase &out = mBody;
2472
2473 if (type.getBasicType() == EbtStruct)
2474 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002475 out << structLookup(type.getTypeName()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002476
2477 const TTypeList *structure = type.getStruct();
2478
2479 for (size_t i = 0; i < structure->size(); i++)
2480 {
2481 const TType *fieldType = (*structure)[i].type;
2482
2483 constUnion = writeConstantUnion(*fieldType, constUnion);
2484
2485 if (i != structure->size() - 1)
2486 {
2487 out << ", ";
2488 }
2489 }
2490
2491 out << ")";
2492 }
2493 else
2494 {
2495 int size = type.getObjectSize();
2496 bool writeType = size > 1;
2497
2498 if (writeType)
2499 {
2500 out << typeString(type) << "(";
2501 }
2502
2503 for (int i = 0; i < size; i++, constUnion++)
2504 {
2505 switch (constUnion->getType())
2506 {
2507 case EbtFloat: out << constUnion->getFConst(); break;
2508 case EbtInt: out << constUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002509 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002510 default: UNREACHABLE();
2511 }
2512
2513 if (i != size - 1)
2514 {
2515 out << ", ";
2516 }
2517 }
2518
2519 if (writeType)
2520 {
2521 out << ")";
2522 }
2523 }
2524
2525 return constUnion;
2526}
2527
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002528TString OutputHLSL::scopeString(unsigned int depthLimit)
2529{
2530 TString string;
2531
2532 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2533 {
2534 string += "_" + str(i);
2535 }
2536
2537 return string;
2538}
2539
2540TString OutputHLSL::scopedStruct(const TString &typeName)
2541{
2542 if (typeName == "")
2543 {
2544 return typeName;
2545 }
2546
2547 return typeName + scopeString(mScopeDepth);
2548}
2549
2550TString OutputHLSL::structLookup(const TString &typeName)
2551{
2552 for (int depth = mScopeDepth; depth >= 0; depth--)
2553 {
2554 TString scopedName = decorate(typeName + scopeString(depth));
2555
2556 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2557 {
2558 if (*structName == scopedName)
2559 {
2560 return scopedName;
2561 }
2562 }
2563 }
2564
2565 UNREACHABLE(); // Should have found a matching constructor
2566
2567 return typeName;
2568}
2569
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002570TString OutputHLSL::decorate(const TString &string)
2571{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002572 if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002573 {
2574 return "_" + string;
2575 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002576
2577 return string;
2578}
2579
apatrick@chromium.org65756022012-01-17 21:45:38 +00002580TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002581{
apatrick@chromium.org65756022012-01-17 21:45:38 +00002582 if (type.isArray())
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002583 {
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002584 return "ar_" + string; // Allows identifying arrays of size 1
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002585 }
apatrick@chromium.org65756022012-01-17 21:45:38 +00002586 else if (type.getBasicType() == EbtSamplerExternalOES)
2587 {
2588 return "ex_" + string;
2589 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002590
2591 return decorate(string);
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002592}
daniel@transgaming.com2e793f02012-04-11 19:41:35 +00002593
2594TString OutputHLSL::decorateField(const TString &string, const TType &structure)
2595{
2596 if (structure.getTypeName().compare(0, 3, "gl_") != 0)
2597 {
2598 return decorate(string);
2599 }
2600
2601 return string;
2602}
daniel@transgaming.com652468c2012-12-20 21:11:57 +00002603
2604TString OutputHLSL::registerString(TIntermSymbol *operand)
2605{
2606 ASSERT(operand->getQualifier() == EvqUniform);
2607
2608 if (IsSampler(operand->getBasicType()))
2609 {
2610 return "s" + str(samplerRegister(operand));
2611 }
2612
2613 return "c" + str(uniformRegister(operand));
2614}
2615
2616int OutputHLSL::samplerRegister(TIntermSymbol *sampler)
2617{
2618 const TType &type = sampler->getType();
2619 ASSERT(IsSampler(type.getBasicType()));
2620
2621 int index = mSamplerRegister;
2622 mSamplerRegister += sampler->totalRegisterCount();
2623
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00002624 declareUniform(type, sampler->getSymbol(), index);
2625
daniel@transgaming.com652468c2012-12-20 21:11:57 +00002626 return index;
2627}
2628
2629int OutputHLSL::uniformRegister(TIntermSymbol *uniform)
2630{
2631 const TType &type = uniform->getType();
2632 ASSERT(!IsSampler(type.getBasicType()));
2633
2634 int index = mUniformRegister;
2635 mUniformRegister += uniform->totalRegisterCount();
2636
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00002637 declareUniform(type, uniform->getSymbol(), index);
2638
daniel@transgaming.com652468c2012-12-20 21:11:57 +00002639 return index;
2640}
2641
daniel@transgaming.comf4d9fef2012-12-20 21:12:13 +00002642void OutputHLSL::declareUniform(const TType &type, const TString &name, int index)
2643{
2644 const TTypeList *structure = type.getStruct();
2645
2646 if (!structure)
2647 {
2648 mActiveUniforms.push_back(Uniform(glVariableType(type), name.c_str(), type.getArraySize(), index));
2649 }
2650 else
2651 {
2652 if (type.isArray())
2653 {
2654 int elementIndex = index;
2655
2656 for (int i = 0; i < type.getArraySize(); i++)
2657 {
2658 for (size_t j = 0; j < structure->size(); j++)
2659 {
2660 const TType &fieldType = *(*structure)[j].type;
2661 const TString &fieldName = fieldType.getFieldName();
2662
2663 const TString uniformName = name + "[" + str(i) + "]." + fieldName;
2664 declareUniform(fieldType, uniformName, elementIndex);
2665 elementIndex += fieldType.elementRegisterCount();
2666 }
2667 }
2668 }
2669 else
2670 {
2671 int fieldIndex = index;
2672
2673 for (size_t i = 0; i < structure->size(); i++)
2674 {
2675 const TType &fieldType = *(*structure)[i].type;
2676 const TString &fieldName = fieldType.getFieldName();
2677
2678 const TString uniformName = name + "." + fieldName;
2679 declareUniform(fieldType, uniformName, fieldIndex);
2680 fieldIndex += fieldType.totalRegisterCount();
2681 }
2682 }
2683 }
2684}
2685
2686GLenum OutputHLSL::glVariableType(const TType &type)
2687{
2688 if (type.getBasicType() == EbtFloat)
2689 {
2690 if (type.isScalar())
2691 {
2692 return GL_FLOAT;
2693 }
2694 else if (type.isVector())
2695 {
2696 switch(type.getNominalSize())
2697 {
2698 case 2: return GL_FLOAT_VEC2;
2699 case 3: return GL_FLOAT_VEC3;
2700 case 4: return GL_FLOAT_VEC4;
2701 default: UNREACHABLE();
2702 }
2703 }
2704 else if (type.isMatrix())
2705 {
2706 switch(type.getNominalSize())
2707 {
2708 case 2: return GL_FLOAT_MAT2;
2709 case 3: return GL_FLOAT_MAT3;
2710 case 4: return GL_FLOAT_MAT4;
2711 default: UNREACHABLE();
2712 }
2713 }
2714 else UNREACHABLE();
2715 }
2716 else if (type.getBasicType() == EbtInt)
2717 {
2718 if (type.isScalar())
2719 {
2720 return GL_INT;
2721 }
2722 else if (type.isVector())
2723 {
2724 switch(type.getNominalSize())
2725 {
2726 case 2: return GL_INT_VEC2;
2727 case 3: return GL_INT_VEC3;
2728 case 4: return GL_INT_VEC4;
2729 default: UNREACHABLE();
2730 }
2731 }
2732 else UNREACHABLE();
2733 }
2734 else if (type.getBasicType() == EbtBool)
2735 {
2736 if (type.isScalar())
2737 {
2738 return GL_BOOL;
2739 }
2740 else if (type.isVector())
2741 {
2742 switch(type.getNominalSize())
2743 {
2744 case 2: return GL_BOOL_VEC2;
2745 case 3: return GL_BOOL_VEC3;
2746 case 4: return GL_BOOL_VEC4;
2747 default: UNREACHABLE();
2748 }
2749 }
2750 else UNREACHABLE();
2751 }
2752 else if (type.getBasicType() == EbtSampler2D)
2753 {
2754 return GL_SAMPLER_2D;
2755 }
2756 else if (type.getBasicType() == EbtSamplerCube)
2757 {
2758 return GL_SAMPLER_CUBE;
2759 }
2760 else UNREACHABLE();
2761
2762 return GL_NONE;
2763}
2764
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002765}