blob: 5400f8c9f40bd7b713219155bca9459888a4a036 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.com15795192011-05-11 15:36:20 +00002// Copyright (c) 2002-2011 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.org91b72322010-06-02 15:50:56 +00009#include "compiler/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "compiler/InfoSink.h"
11#include "compiler/UnfoldSelect.h"
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +000012#include "compiler/SearchSymbol.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
apatrick@chromium.orgbad6c2a2010-07-20 20:19:51 +000014#include <stdio.h>
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +000015#include <algorithm>
16
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017namespace sh
18{
daniel@transgaming.com005c7392010-04-15 20:45:27 +000019// Integer to TString conversion
20TString str(int i)
21{
22 char buffer[20];
23 sprintf(buffer, "%d", i);
24 return buffer;
25}
26
daniel@transgaming.com950f9932010-04-13 03:26:14 +000027OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028{
daniel@transgaming.comb5875982010-04-15 20:44:53 +000029 mUnfoldSelect = new UnfoldSelect(context, this);
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +000030 mInsideFunction = false;
daniel@transgaming.comb5875982010-04-15 20:44:53 +000031
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000032 mUsesTexture2D = false;
33 mUsesTexture2D_bias = false;
34 mUsesTexture2DProj = false;
35 mUsesTexture2DProj_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000036 mUsesTexture2DProjLod = false;
37 mUsesTexture2DLod = false;
daniel@transgaming.com5024cc42010-04-20 18:52:04 +000038 mUsesTextureCube = false;
39 mUsesTextureCube_bias = false;
daniel@transgaming.com15795192011-05-11 15:36:20 +000040 mUsesTextureCubeLod = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000041 mUsesDepthRange = false;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000042 mUsesFragCoord = false;
43 mUsesPointCoord = false;
44 mUsesFrontFacing = false;
45 mUsesPointSize = false;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +000046 mUsesXor = false;
47 mUsesMod1 = false;
daniel@transgaming.com4229f592011-11-24 22:34:04 +000048 mUsesMod2v = false;
49 mUsesMod2f = false;
50 mUsesMod3v = false;
51 mUsesMod3f = false;
52 mUsesMod4v = false;
53 mUsesMod4f = false;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +000054 mUsesFaceforward1 = false;
55 mUsesFaceforward2 = false;
56 mUsesFaceforward3 = false;
57 mUsesFaceforward4 = false;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +000058 mUsesEqualMat2 = false;
59 mUsesEqualMat3 = false;
60 mUsesEqualMat4 = false;
61 mUsesEqualVec2 = false;
62 mUsesEqualVec3 = false;
63 mUsesEqualVec4 = false;
64 mUsesEqualIVec2 = false;
65 mUsesEqualIVec3 = false;
66 mUsesEqualIVec4 = false;
67 mUsesEqualBVec2 = false;
68 mUsesEqualBVec3 = false;
69 mUsesEqualBVec4 = false;
daniel@transgaming.com0f189612010-05-07 13:03:36 +000070 mUsesAtan2 = false;
daniel@transgaming.com005c7392010-04-15 20:45:27 +000071
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +000072 mScopeDepth = 0;
73
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +000074 mUniqueIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
daniel@transgaming.comb5875982010-04-15 20:44:53 +000077OutputHLSL::~OutputHLSL()
78{
79 delete mUnfoldSelect;
80}
81
daniel@transgaming.com950f9932010-04-13 03:26:14 +000082void OutputHLSL::output()
83{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000084 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 +000085 header();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000086
87 mContext.infoSink.obj << mHeader.c_str();
88 mContext.infoSink.obj << mBody.c_str();
daniel@transgaming.com950f9932010-04-13 03:26:14 +000089}
90
daniel@transgaming.comb5875982010-04-15 20:44:53 +000091TInfoSinkBase &OutputHLSL::getBodyStream()
92{
93 return mBody;
94}
95
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +000096int OutputHLSL::vectorSize(const TType &type) const
97{
98 int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
99 int arraySize = type.isArray() ? type.getArraySize() : 1;
100
101 return elementSize * arraySize;
102}
103
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104void OutputHLSL::header()
105{
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000106 ShShaderType shaderType = mContext.shaderType;
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000107 TInfoSinkBase &out = mHeader;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000109 for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000110 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000111 out << *structDeclaration;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000112 }
113
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000114 for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000115 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +0000116 out << *constructor;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000117 }
118
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000119 if (shaderType == SH_FRAGMENT_SHADER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120 {
121 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000122 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000124 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 int semanticIndex = 0;
126
127 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
128 {
129 const TSymbol *symbol = (*namedSymbol).second;
130 const TString &name = symbol->getName();
131
132 if (symbol->isVariable())
133 {
134 const TVariable *variable = static_cast<const TVariable*>(symbol);
135 const TType &type = variable->getType();
136 TQualifier qualifier = type.getQualifier();
137
138 if (qualifier == EvqUniform)
139 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000140 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
141 {
apatrick@chromium.org65756022012-01-17 21:45:38 +0000142 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000143 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 }
145 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
146 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000147 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
148 {
149 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000150 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com005c7392010-04-15 20:45:27 +0000151
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000152 semanticIndex += type.isArray() ? type.getArraySize() : 1;
153 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000155 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000156 {
157 // Globals are declared and intialized as an aggregate node
158 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000159 else if (qualifier == EvqConst)
160 {
161 // Constants are repeated as literals where used
162 }
163 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 }
165 }
166
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000167 out << "// Varyings\n";
168 out << varyings;
169 out << "\n"
170 "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
171
172 if (mUsesFragCoord)
173 {
174 out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
175 }
176
177 if (mUsesPointCoord)
178 {
179 out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
180 }
181
182 if (mUsesFrontFacing)
183 {
184 out << "static bool gl_FrontFacing = false;\n";
185 }
186
187 out << "\n";
188
189 if (mUsesFragCoord)
190 {
daniel@transgaming.comd9a54f92011-12-22 18:32:53 +0000191 out << "uniform float4 dx_Coord;\n"
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000192 "uniform float2 dx_Depth;\n";
193 }
194
195 if (mUsesFrontFacing)
196 {
197 out << "uniform bool dx_PointsOrLines;\n"
198 "uniform bool dx_FrontCCW;\n";
199 }
200
201 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 out << uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000203 out << "\n";
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000204
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000205 // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
206 // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
207 // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
208 // convention, the Y coordinate passed to these functions is adjusted to compensate.
209 //
210 // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
211 //
212 // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
213 // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
214 //
215 // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
216 // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
217 // +Y and -Y faces everywhere else throughout the code.
218
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000219 if (mUsesTexture2D)
220 {
221 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
222 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000223 " return tex2D(s, float2(t.x, 1 - t.y));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000224 "}\n"
225 "\n";
226 }
227
228 if (mUsesTexture2D_bias)
229 {
230 out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
231 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000232 " return tex2Dbias(s, float4(t.x, 1 - t.y, 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000233 "}\n"
234 "\n";
235 }
236
237 if (mUsesTexture2DProj)
238 {
239 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
240 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000241 " return tex2Dproj(s, float4(t.x, t.z - t.y, 0, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000242 "}\n"
243 "\n"
244 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
245 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000246 " return tex2Dproj(s, float4(t.x, t.w - t.y, t.z, t.w));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000247 "}\n"
248 "\n";
249 }
250
251 if (mUsesTexture2DProj_bias)
252 {
253 out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
254 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000255 " return tex2Dbias(s, float4(t.x / t.z, 1 - (t.y / t.z), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000256 "}\n"
257 "\n"
258 "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
259 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000260 " return tex2Dbias(s, float4(t.x / t.w, 1 - (t.y / t.w), 0, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000261 "}\n"
262 "\n";
263 }
264
265 if (mUsesTextureCube)
266 {
267 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
268 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000269 " return texCUBE(s, float3(t.x, -t.y, t.z));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000270 "}\n"
271 "\n";
272 }
273
274 if (mUsesTextureCube_bias)
275 {
276 out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
277 "{\n"
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +0000278 " return texCUBEbias(s, float4(t.x, -t.y, t.z, bias));\n"
daniel@transgaming.com5024cc42010-04-20 18:52:04 +0000279 "}\n"
280 "\n";
281 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282 }
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000283 else // Vertex shader
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 {
285 TString uniforms;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000286 TString attributes;
287 TString varyings;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000289 TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290
291 for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
292 {
293 const TSymbol *symbol = (*namedSymbol).second;
294 const TString &name = symbol->getName();
295
296 if (symbol->isVariable())
297 {
298 const TVariable *variable = static_cast<const TVariable*>(symbol);
299 const TType &type = variable->getType();
300 TQualifier qualifier = type.getQualifier();
301
302 if (qualifier == EvqUniform)
303 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000304 if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
305 {
apatrick@chromium.org65756022012-01-17 21:45:38 +0000306 uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000307 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308 }
309 else if (qualifier == EvqAttribute)
310 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000311 if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
312 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000313 attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000314 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315 }
316 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
317 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000318 if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
319 {
320 // Program linking depends on this exact format
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000321 varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000322 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000324 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
daniel@transgaming.comd25ab252010-03-30 03:36:26 +0000326 // Globals are declared and intialized as an aggregate node
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000328 else if (qualifier == EvqConst)
329 {
330 // Constants are repeated as literals where used
331 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 else UNREACHABLE();
333 }
334 }
335
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000336 out << "// Attributes\n";
337 out << attributes;
338 out << "\n"
339 "static float4 gl_Position = float4(0, 0, 0, 0);\n";
340
341 if (mUsesPointSize)
342 {
343 out << "static float gl_PointSize = float(1);\n";
344 }
345
346 out << "\n"
347 "// Varyings\n";
348 out << varyings;
349 out << "\n"
350 "uniform float2 dx_HalfPixelSize;\n"
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000351 "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 out << uniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353 out << "\n";
daniel@transgaming.com15795192011-05-11 15:36:20 +0000354
355 // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
356 // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
357 // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
358 // convention, the Y coordinate passed to these functions is adjusted to compensate.
359 //
360 // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
361 //
362 // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
363 // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
364 //
365 // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
366 // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
367 // +Y and -Y faces everywhere else throughout the code.
368
369 if (mUsesTexture2D)
370 {
371 out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
372 "{\n"
373 " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, 0));\n"
374 "}\n"
375 "\n";
376 }
377
378 if (mUsesTexture2DLod)
379 {
380 out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
381 "{\n"
382 " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, lod));\n"
383 "}\n"
384 "\n";
385 }
386
387 if (mUsesTexture2DProj)
388 {
389 out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
390 "{\n"
391 " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, 0));\n"
392 "}\n"
393 "\n"
394 "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
395 "{\n"
396 " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, 0));\n"
397 "}\n"
398 "\n";
399 }
400
401 if (mUsesTexture2DProjLod)
402 {
403 out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
404 "{\n"
405 " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, lod));\n"
406 "}\n"
407 "\n"
408 "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
409 "{\n"
410 " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, lod));\n"
411 "}\n"
412 "\n";
413 }
414
415 if (mUsesTextureCube)
416 {
417 out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
418 "{\n"
419 " return texCUBElod(s, float4(t.x, -t.y, t.z, 0));\n"
420 "}\n"
421 "\n";
422 }
423
424 if (mUsesTextureCubeLod)
425 {
426 out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
427 "{\n"
428 " return texCUBElod(s, float4(t.x, -t.y, t.z, lod));\n"
429 "}\n"
430 "\n";
431 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432 }
433
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000434 if (mUsesFragCoord)
435 {
436 out << "#define GL_USES_FRAG_COORD\n";
437 }
438
439 if (mUsesPointCoord)
440 {
441 out << "#define GL_USES_POINT_COORD\n";
442 }
443
444 if (mUsesFrontFacing)
445 {
446 out << "#define GL_USES_FRONT_FACING\n";
447 }
448
449 if (mUsesPointSize)
450 {
451 out << "#define GL_USES_POINT_SIZE\n";
452 }
453
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000454 if (mUsesDepthRange)
455 {
456 out << "struct gl_DepthRangeParameters\n"
457 "{\n"
458 " float near;\n"
459 " float far;\n"
460 " float diff;\n"
461 "};\n"
462 "\n"
daniel@transgaming.com31754962010-11-28 02:02:52 +0000463 "uniform float3 dx_DepthRange;"
464 "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000465 "\n";
466 }
467
468 if (mUsesXor)
469 {
470 out << "bool xor(bool p, bool q)\n"
471 "{\n"
472 " return (p || q) && !(p && q);\n"
473 "}\n"
474 "\n";
475 }
476
477 if (mUsesMod1)
478 {
479 out << "float mod(float x, float y)\n"
480 "{\n"
481 " return x - y * floor(x / y);\n"
482 "}\n"
483 "\n";
484 }
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000485
486 if (mUsesMod2v)
487 {
488 out << "float2 mod(float2 x, float2 y)\n"
489 "{\n"
490 " return x - y * floor(x / y);\n"
491 "}\n"
492 "\n";
493 }
494
495 if (mUsesMod2f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000496 {
497 out << "float2 mod(float2 x, float y)\n"
498 "{\n"
499 " return x - y * floor(x / y);\n"
500 "}\n"
501 "\n";
502 }
503
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000504 if (mUsesMod3v)
505 {
506 out << "float3 mod(float3 x, float3 y)\n"
507 "{\n"
508 " return x - y * floor(x / y);\n"
509 "}\n"
510 "\n";
511 }
512
513 if (mUsesMod3f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000514 {
515 out << "float3 mod(float3 x, float y)\n"
516 "{\n"
517 " return x - y * floor(x / y);\n"
518 "}\n"
519 "\n";
520 }
521
daniel@transgaming.com4229f592011-11-24 22:34:04 +0000522 if (mUsesMod4v)
523 {
524 out << "float4 mod(float4 x, float4 y)\n"
525 "{\n"
526 " return x - y * floor(x / y);\n"
527 "}\n"
528 "\n";
529 }
530
531 if (mUsesMod4f)
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000532 {
533 out << "float4 mod(float4 x, float y)\n"
534 "{\n"
535 " return x - y * floor(x / y);\n"
536 "}\n"
537 "\n";
538 }
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000539
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000540 if (mUsesFaceforward1)
541 {
542 out << "float faceforward(float N, float I, float Nref)\n"
543 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000544 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000545 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000546 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000547 " }\n"
548 " else\n"
549 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000550 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000551 " }\n"
552 "}\n"
553 "\n";
554 }
555
556 if (mUsesFaceforward2)
557 {
558 out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
559 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000560 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000561 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000562 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000563 " }\n"
564 " else\n"
565 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000566 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000567 " }\n"
568 "}\n"
569 "\n";
570 }
571
572 if (mUsesFaceforward3)
573 {
574 out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
575 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000576 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000577 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000578 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000579 " }\n"
580 " else\n"
581 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000582 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000583 " }\n"
584 "}\n"
585 "\n";
586 }
587
588 if (mUsesFaceforward4)
589 {
590 out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
591 "{\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000592 " if(dot(Nref, I) >= 0)\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000593 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000594 " return -N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000595 " }\n"
596 " else\n"
597 " {\n"
daniel@transgaming.com3debd2b2010-05-13 02:07:34 +0000598 " return N;\n"
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +0000599 " }\n"
600 "}\n"
601 "\n";
602 }
603
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000604 if (mUsesEqualMat2)
605 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000606 out << "bool equal(float2x2 m, float2x2 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000607 "{\n"
608 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
609 " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
610 "}\n";
611 }
612
613 if (mUsesEqualMat3)
614 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000615 out << "bool equal(float3x3 m, float3x3 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000616 "{\n"
617 " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
618 " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
619 " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
620 "}\n";
621 }
622
623 if (mUsesEqualMat4)
624 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000625 out << "bool equal(float4x4 m, float4x4 n)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000626 "{\n"
627 " 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"
628 " 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"
629 " 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"
630 " 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"
631 "}\n";
632 }
633
634 if (mUsesEqualVec2)
635 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000636 out << "bool equal(float2 v, float2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000637 "{\n"
638 " return v.x == u.x && v.y == u.y;\n"
639 "}\n";
640 }
641
642 if (mUsesEqualVec3)
643 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000644 out << "bool equal(float3 v, float3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000645 "{\n"
646 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
647 "}\n";
648 }
649
650 if (mUsesEqualVec4)
651 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000652 out << "bool equal(float4 v, float4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000653 "{\n"
654 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
655 "}\n";
656 }
657
658 if (mUsesEqualIVec2)
659 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000660 out << "bool equal(int2 v, int2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000661 "{\n"
662 " return v.x == u.x && v.y == u.y;\n"
663 "}\n";
664 }
665
666 if (mUsesEqualIVec3)
667 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000668 out << "bool equal(int3 v, int3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000669 "{\n"
670 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
671 "}\n";
672 }
673
674 if (mUsesEqualIVec4)
675 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000676 out << "bool equal(int4 v, int4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000677 "{\n"
678 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
679 "}\n";
680 }
681
682 if (mUsesEqualBVec2)
683 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000684 out << "bool equal(bool2 v, bool2 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000685 "{\n"
686 " return v.x == u.x && v.y == u.y;\n"
687 "}\n";
688 }
689
690 if (mUsesEqualBVec3)
691 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000692 out << "bool equal(bool3 v, bool3 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000693 "{\n"
694 " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
695 "}\n";
696 }
697
698 if (mUsesEqualBVec4)
699 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000700 out << "bool equal(bool4 v, bool4 u)\n"
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000701 "{\n"
702 " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
703 "}\n";
704 }
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000705
706 if (mUsesAtan2)
707 {
708 out << "float atanyx(float y, float x)\n"
709 "{\n"
710 " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
711 " return atan2(y, x);\n"
712 "}\n";
713 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000714}
715
716void OutputHLSL::visitSymbol(TIntermSymbol *node)
717{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000718 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000719
720 TString name = node->getSymbol();
721
722 if (name == "gl_FragColor")
723 {
724 out << "gl_Color[0]";
725 }
726 else if (name == "gl_FragData")
727 {
728 out << "gl_Color";
729 }
daniel@transgaming.comd7c98102010-05-14 17:30:48 +0000730 else if (name == "gl_DepthRange")
731 {
732 mUsesDepthRange = true;
733 out << name;
734 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000735 else if (name == "gl_FragCoord")
736 {
737 mUsesFragCoord = true;
738 out << name;
739 }
740 else if (name == "gl_PointCoord")
741 {
742 mUsesPointCoord = true;
743 out << name;
744 }
745 else if (name == "gl_FrontFacing")
746 {
747 mUsesFrontFacing = true;
748 out << name;
749 }
750 else if (name == "gl_PointSize")
751 {
752 mUsesPointSize = true;
753 out << name;
754 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000755 else
756 {
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000757 TQualifier qualifier = node->getQualifier();
758
759 if (qualifier == EvqUniform)
760 {
761 mReferencedUniforms.insert(name.c_str());
apatrick@chromium.org65756022012-01-17 21:45:38 +0000762 out << decorateUniform(name, node->getType());
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000763 }
764 else if (qualifier == EvqAttribute)
765 {
766 mReferencedAttributes.insert(name.c_str());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000767 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000768 }
769 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
770 {
771 mReferencedVaryings.insert(name.c_str());
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000772 out << decorate(name);
daniel@transgaming.com86f7c9d2010-04-20 18:52:06 +0000773 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +0000774 else
775 {
776 out << decorate(name);
777 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778 }
779}
780
781bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
782{
daniel@transgaming.com950f9932010-04-13 03:26:14 +0000783 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000784
785 switch (node->getOp())
786 {
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000787 case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000788 case EOpInitialize:
789 if (visit == PreVisit)
790 {
791 // GLSL allows to write things like "float x = x;" where a new variable x is defined
792 // and the value of an existing variable x is assigned. HLSL uses C semantics (the
793 // new variable is created before the assignment is evaluated), so we need to convert
794 // this to "float t = x, x = t;".
795
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000796 TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
797 TIntermTyped *expression = node->getRight();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000798
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000799 sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
800 expression->traverse(&searchSymbol);
801 bool sameSymbol = searchSymbol.foundMatch();
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000802
daniel@transgaming.combdfb2e52010-11-15 16:41:20 +0000803 if (sameSymbol)
804 {
805 // Type already printed
806 out << "t" + str(mUniqueIndex) + " = ";
807 expression->traverse(this);
808 out << ", ";
809 symbolNode->traverse(this);
810 out << " = t" + str(mUniqueIndex);
811
812 mUniqueIndex++;
813 return false;
814 }
815 }
816 else if (visit == InVisit)
817 {
818 out << " = ";
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +0000819 }
820 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000821 case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
822 case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
823 case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
824 case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
825 case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
826 case EOpVectorTimesMatrixAssign:
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000827 if (visit == PreVisit)
828 {
829 out << "(";
830 }
831 else if (visit == InVisit)
832 {
833 out << " = mul(";
834 node->getLeft()->traverse(this);
835 out << ", transpose(";
836 }
837 else
838 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000839 out << ")))";
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000840 }
841 break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000842 case EOpMatrixTimesMatrixAssign:
843 if (visit == PreVisit)
844 {
845 out << "(";
846 }
847 else if (visit == InVisit)
848 {
849 out << " = mul(";
850 node->getLeft()->traverse(this);
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +0000851 out << ", ";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000852 }
853 else
854 {
daniel@transgaming.com3aa74202010-04-29 03:39:04 +0000855 out << "))";
daniel@transgaming.com93a96c32010-03-28 19:36:13 +0000856 }
857 break;
858 case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +0000859 case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
860 case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +0000861 case EOpIndexDirectStruct:
862 if (visit == InVisit)
863 {
864 out << "." + node->getType().getFieldName();
865
866 return false;
867 }
868 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000869 case EOpVectorSwizzle:
870 if (visit == InVisit)
871 {
872 out << ".";
873
874 TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
875
876 if (swizzle)
877 {
878 TIntermSequence &sequence = swizzle->getSequence();
879
880 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
881 {
882 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
883
884 if (element)
885 {
886 int i = element->getUnionArrayPointer()[0].getIConst();
887
888 switch (i)
889 {
890 case 0: out << "x"; break;
891 case 1: out << "y"; break;
892 case 2: out << "z"; break;
893 case 3: out << "w"; break;
894 default: UNREACHABLE();
895 }
896 }
897 else UNREACHABLE();
898 }
899 }
900 else UNREACHABLE();
901
902 return false; // Fully processed
903 }
904 break;
905 case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
906 case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
907 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
908 case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000909 case EOpEqual:
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000910 case EOpNotEqual:
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000911 if (node->getLeft()->isScalar())
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000912 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000913 if (node->getOp() == EOpEqual)
914 {
915 outputTriplet(visit, "(", " == ", ")");
916 }
917 else
918 {
919 outputTriplet(visit, "(", " != ", ")");
920 }
921 }
922 else if (node->getLeft()->getBasicType() == EbtStruct)
923 {
924 if (node->getOp() == EOpEqual)
925 {
926 out << "(";
927 }
928 else
929 {
930 out << "!(";
931 }
932
933 const TTypeList *fields = node->getLeft()->getType().getStruct();
934
935 for (size_t i = 0; i < fields->size(); i++)
936 {
937 const TType *fieldType = (*fields)[i].type;
938
939 node->getLeft()->traverse(this);
940 out << "." + fieldType->getFieldName() + " == ";
941 node->getRight()->traverse(this);
942 out << "." + fieldType->getFieldName();
943
944 if (i < fields->size() - 1)
945 {
946 out << " && ";
947 }
948 }
949
950 out << ")";
951
952 return false;
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +0000953 }
954 else
955 {
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000956 if (node->getLeft()->isMatrix())
957 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000958 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000959 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000960 case 2: mUsesEqualMat2 = true; break;
961 case 3: mUsesEqualMat3 = true; break;
962 case 4: mUsesEqualMat4 = true; break;
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000963 default: UNREACHABLE();
964 }
965 }
966 else if (node->getLeft()->isVector())
967 {
968 switch (node->getLeft()->getBasicType())
969 {
970 case EbtFloat:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000971 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000972 {
973 case 2: mUsesEqualVec2 = true; break;
974 case 3: mUsesEqualVec3 = true; break;
975 case 4: mUsesEqualVec4 = true; break;
976 default: UNREACHABLE();
977 }
978 break;
979 case EbtInt:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000980 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000981 {
982 case 2: mUsesEqualIVec2 = true; break;
983 case 3: mUsesEqualIVec3 = true; break;
984 case 4: mUsesEqualIVec4 = true; break;
985 default: UNREACHABLE();
986 }
987 break;
988 case EbtBool:
alokp@chromium.org58e54292010-08-24 21:40:03 +0000989 switch (node->getLeft()->getNominalSize())
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +0000990 {
991 case 2: mUsesEqualBVec2 = true; break;
992 case 3: mUsesEqualBVec3 = true; break;
993 case 4: mUsesEqualBVec4 = true; break;
994 default: UNREACHABLE();
995 }
996 break;
997 default: UNREACHABLE();
998 }
999 }
1000 else UNREACHABLE();
1001
1002 if (node->getOp() == EOpEqual)
1003 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001004 outputTriplet(visit, "equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001005 }
1006 else
1007 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001008 outputTriplet(visit, "!equal(", ", ", ")");
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001009 }
daniel@transgaming.com49bce7e2010-03-17 03:58:51 +00001010 }
1011 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001012 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1013 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1014 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1015 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1016 case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com93a96c32010-03-28 19:36:13 +00001017 case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com8976c1e2010-04-13 19:53:27 +00001018 case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
1019 case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
daniel@transgaming.com69f084b2010-04-23 18:34:46 +00001020 case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001021 case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001022 case EOpLogicalXor:
1023 mUsesXor = true;
1024 outputTriplet(visit, "xor(", ", ", ")");
1025 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001026 case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
1027 default: UNREACHABLE();
1028 }
1029
1030 return true;
1031}
1032
1033bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
1034{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001035 switch (node->getOp())
1036 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001037 case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
1038 case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1039 case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
1040 case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
1041 case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
1042 case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
1043 case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044 case EOpConvIntToBool:
1045 case EOpConvFloatToBool:
1046 switch (node->getOperand()->getType().getNominalSize())
1047 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001048 case 1: outputTriplet(visit, "bool(", "", ")"); break;
1049 case 2: outputTriplet(visit, "bool2(", "", ")"); break;
1050 case 3: outputTriplet(visit, "bool3(", "", ")"); break;
1051 case 4: outputTriplet(visit, "bool4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001052 default: UNREACHABLE();
1053 }
1054 break;
1055 case EOpConvBoolToFloat:
1056 case EOpConvIntToFloat:
1057 switch (node->getOperand()->getType().getNominalSize())
1058 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001059 case 1: outputTriplet(visit, "float(", "", ")"); break;
1060 case 2: outputTriplet(visit, "float2(", "", ")"); break;
1061 case 3: outputTriplet(visit, "float3(", "", ")"); break;
1062 case 4: outputTriplet(visit, "float4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063 default: UNREACHABLE();
1064 }
1065 break;
1066 case EOpConvFloatToInt:
1067 case EOpConvBoolToInt:
1068 switch (node->getOperand()->getType().getNominalSize())
1069 {
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001070 case 1: outputTriplet(visit, "int(", "", ")"); break;
1071 case 2: outputTriplet(visit, "int2(", "", ")"); break;
1072 case 3: outputTriplet(visit, "int3(", "", ")"); break;
1073 case 4: outputTriplet(visit, "int4(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 default: UNREACHABLE();
1075 }
1076 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001077 case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
1078 case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
1079 case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
1080 case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
1081 case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
1082 case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
1083 case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
1084 case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
1085 case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
1086 case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
1087 case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
1088 case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
1089 case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
1090 case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
1091 case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
1092 case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
1093 case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
1094 case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
1095 case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
1096 case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
1097 case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +00001098 case EOpDFdx: outputTriplet(visit, "ddx(", "", ")"); break;
apatrick@chromium.orgb31f5322011-01-19 19:02:52 +00001099 case EOpDFdy: outputTriplet(visit, "(-ddy(", "", "))"); break;
alokp@chromium.org06098892010-08-26 19:36:42 +00001100 case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001101 case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
1102 case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001103 default: UNREACHABLE();
1104 }
1105
1106 return true;
1107}
1108
1109bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1110{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001111 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001112
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001113 switch (node->getOp())
1114 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001115 case EOpSequence:
1116 {
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001117 if (mInsideFunction)
1118 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001119 outputLineDirective(node->getLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001120 out << "{\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001121
1122 mScopeDepth++;
1123
1124 if (mScopeBracket.size() < mScopeDepth)
1125 {
1126 mScopeBracket.push_back(0); // New scope level
1127 }
1128 else
1129 {
1130 mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
1131 }
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001132 }
1133
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001134 for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1135 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001136 outputLineDirective((*sit)->getLine());
1137
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001138 if (isSingleStatement(*sit))
1139 {
1140 mUnfoldSelect->traverse(*sit);
1141 }
1142
1143 (*sit)->traverse(this);
1144
1145 out << ";\n";
1146 }
1147
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001148 if (mInsideFunction)
1149 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001150 outputLineDirective(node->getEndLine());
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001151 out << "}\n";
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001152
1153 mScopeDepth--;
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001154 }
1155
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001156 return false;
1157 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001158 case EOpDeclaration:
1159 if (visit == PreVisit)
1160 {
1161 TIntermSequence &sequence = node->getSequence();
1162 TIntermTyped *variable = sequence[0]->getAsTyped();
1163 bool visit = true;
1164
daniel@transgaming.comd25ab252010-03-30 03:36:26 +00001165 if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001166 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001167 if (variable->getType().getStruct())
1168 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001169 addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
daniel@transgaming.comead23042010-04-29 03:35:36 +00001170 }
1171
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001172 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001173 {
daniel@transgaming.comd2cf25d2010-04-22 16:27:35 +00001174 if (!mInsideFunction)
daniel@transgaming.comd91cfe72010-04-13 03:26:17 +00001175 {
1176 out << "static ";
1177 }
1178
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001179 out << typeString(variable->getType()) + " ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001180
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001181 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001182 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001183 TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001184
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001185 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001186 {
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001187 symbol->traverse(this);
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001188 out << arrayString(symbol->getType());
daniel@transgaming.com7127f202010-04-15 20:45:22 +00001189 out << " = " + initializer(variable->getType());
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001190 }
1191 else
1192 {
1193 (*sit)->traverse(this);
1194 }
1195
1196 if (visit && this->inVisit)
1197 {
1198 if (*sit != sequence.back())
1199 {
1200 visit = this->visitAggregate(InVisit, node);
1201 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001202 }
1203 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001204
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001205 if (visit && this->postVisit)
1206 {
1207 this->visitAggregate(PostVisit, node);
1208 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001210 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
1211 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00001212 // Already added to constructor map
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001213 }
1214 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215 }
1216
1217 return false;
1218 }
1219 else if (visit == InVisit)
1220 {
1221 out << ", ";
1222 }
1223 break;
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001224 case EOpPrototype:
1225 if (visit == PreVisit)
1226 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001227 out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001228
1229 TIntermSequence &arguments = node->getSequence();
1230
1231 for (unsigned int i = 0; i < arguments.size(); i++)
1232 {
1233 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1234
1235 if (symbol)
1236 {
1237 out << argumentString(symbol);
1238
1239 if (i < arguments.size() - 1)
1240 {
1241 out << ", ";
1242 }
1243 }
1244 else UNREACHABLE();
1245 }
1246
1247 out << ");\n";
1248
1249 return false;
1250 }
1251 break;
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001252 case EOpComma: outputTriplet(visit, "", ", ", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001253 case EOpFunction:
1254 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001255 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001256
1257 if (visit == PreVisit)
1258 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001259 out << typeString(node->getType()) << " ";
1260
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261 if (name == "main")
1262 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001263 out << "gl_main(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264 }
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001265 else
1266 {
1267 out << decorate(name) << "(";
1268 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001269
1270 TIntermSequence &sequence = node->getSequence();
1271 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1272
1273 for (unsigned int i = 0; i < arguments.size(); i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001275 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001276
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001277 if (symbol)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001278 {
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001279 out << argumentString(symbol);
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001280
1281 if (i < arguments.size() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001282 {
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001283 out << ", ";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001284 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001285 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001286 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001287 }
daniel@transgaming.come78c0c92010-03-28 19:36:06 +00001288
1289 sequence.erase(sequence.begin());
1290
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001291 out << ")\n";
1292
1293 outputLineDirective(node->getLine());
1294 out << "{\n";
1295
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001296 mInsideFunction = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001297 }
1298 else if (visit == PostVisit)
1299 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001300 outputLineDirective(node->getEndLine());
daniel@transgaming.com63691862010-04-29 03:32:42 +00001301 out << "}\n";
1302
daniel@transgaming.comf9ef1072010-04-22 13:35:16 +00001303 mInsideFunction = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001304 }
1305 }
1306 break;
1307 case EOpFunctionCall:
1308 {
1309 if (visit == PreVisit)
1310 {
alokp@chromium.org43884872010-03-30 00:08:52 +00001311 TString name = TFunction::unmangleName(node->getName());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001312
1313 if (node->isUserDefined())
1314 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001315 out << decorate(name) << "(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 }
1317 else
1318 {
1319 if (name == "texture2D")
1320 {
1321 if (node->getSequence().size() == 2)
1322 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001323 mUsesTexture2D = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001324 }
1325 else if (node->getSequence().size() == 3)
1326 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001327 mUsesTexture2D_bias = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001328 }
1329 else UNREACHABLE();
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001330
1331 out << "gl_texture2D(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001332 }
1333 else if (name == "texture2DProj")
1334 {
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001335 if (node->getSequence().size() == 2)
1336 {
1337 mUsesTexture2DProj = true;
1338 }
1339 else if (node->getSequence().size() == 3)
1340 {
1341 mUsesTexture2DProj_bias = true;
1342 }
1343 else UNREACHABLE();
1344
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001345 out << "gl_texture2DProj(";
1346 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001347 else if (name == "textureCube")
1348 {
1349 if (node->getSequence().size() == 2)
1350 {
1351 mUsesTextureCube = true;
1352 }
1353 else if (node->getSequence().size() == 3)
1354 {
1355 mUsesTextureCube_bias = true;
1356 }
1357 else UNREACHABLE();
1358
1359 out << "gl_textureCube(";
1360 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001361 else if (name == "texture2DLod")
1362 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001363 if (node->getSequence().size() == 3)
1364 {
1365 mUsesTexture2DLod = true;
1366 }
1367 else UNREACHABLE();
1368
1369 out << "gl_texture2DLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001370 }
1371 else if (name == "texture2DProjLod")
1372 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001373 if (node->getSequence().size() == 3)
1374 {
1375 mUsesTexture2DProjLod = true;
1376 }
1377 else UNREACHABLE();
1378
1379 out << "gl_texture2DProjLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001380 }
daniel@transgaming.com5024cc42010-04-20 18:52:04 +00001381 else if (name == "textureCubeLod")
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001382 {
daniel@transgaming.com15795192011-05-11 15:36:20 +00001383 if (node->getSequence().size() == 3)
1384 {
1385 mUsesTextureCubeLod = true;
1386 }
1387 else UNREACHABLE();
1388
1389 out << "gl_textureCubeLod(";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001390 }
daniel@transgaming.comec55d292010-04-15 20:44:49 +00001391 else UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001392 }
1393 }
1394 else if (visit == InVisit)
1395 {
1396 out << ", ";
1397 }
1398 else
1399 {
1400 out << ")";
1401 }
1402 }
1403 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001404 case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001405 case EOpConstructFloat:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001406 addConstructor(node->getType(), "vec1", &node->getSequence());
1407 outputTriplet(visit, "vec1(", "", ")");
1408 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001409 case EOpConstructVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001410 addConstructor(node->getType(), "vec2", &node->getSequence());
1411 outputTriplet(visit, "vec2(", ", ", ")");
1412 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001413 case EOpConstructVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001414 addConstructor(node->getType(), "vec3", &node->getSequence());
1415 outputTriplet(visit, "vec3(", ", ", ")");
1416 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001417 case EOpConstructVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001418 addConstructor(node->getType(), "vec4", &node->getSequence());
1419 outputTriplet(visit, "vec4(", ", ", ")");
1420 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001421 case EOpConstructBool:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001422 addConstructor(node->getType(), "bvec1", &node->getSequence());
1423 outputTriplet(visit, "bvec1(", "", ")");
1424 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001425 case EOpConstructBVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001426 addConstructor(node->getType(), "bvec2", &node->getSequence());
1427 outputTriplet(visit, "bvec2(", ", ", ")");
1428 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001429 case EOpConstructBVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001430 addConstructor(node->getType(), "bvec3", &node->getSequence());
1431 outputTriplet(visit, "bvec3(", ", ", ")");
1432 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001433 case EOpConstructBVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001434 addConstructor(node->getType(), "bvec4", &node->getSequence());
1435 outputTriplet(visit, "bvec4(", ", ", ")");
1436 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001437 case EOpConstructInt:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001438 addConstructor(node->getType(), "ivec1", &node->getSequence());
1439 outputTriplet(visit, "ivec1(", "", ")");
1440 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001441 case EOpConstructIVec2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001442 addConstructor(node->getType(), "ivec2", &node->getSequence());
1443 outputTriplet(visit, "ivec2(", ", ", ")");
1444 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001445 case EOpConstructIVec3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001446 addConstructor(node->getType(), "ivec3", &node->getSequence());
1447 outputTriplet(visit, "ivec3(", ", ", ")");
1448 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001449 case EOpConstructIVec4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001450 addConstructor(node->getType(), "ivec4", &node->getSequence());
1451 outputTriplet(visit, "ivec4(", ", ", ")");
1452 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001453 case EOpConstructMat2:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001454 addConstructor(node->getType(), "mat2", &node->getSequence());
1455 outputTriplet(visit, "mat2(", ", ", ")");
1456 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001457 case EOpConstructMat3:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001458 addConstructor(node->getType(), "mat3", &node->getSequence());
1459 outputTriplet(visit, "mat3(", ", ", ")");
1460 break;
daniel@transgaming.com63691862010-04-29 03:32:42 +00001461 case EOpConstructMat4:
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001462 addConstructor(node->getType(), "mat4", &node->getSequence());
1463 outputTriplet(visit, "mat4(", ", ", ")");
1464 break;
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001465 case EOpConstructStruct:
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001466 addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1467 outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00001468 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001469 case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
1470 case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
1471 case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
1472 case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
1473 case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
1474 case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001475 case EOpMod:
1476 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001477 // We need to look at the number of components in both arguments
1478 switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
1479 + node->getSequence()[1]->getAsTyped()->getNominalSize())
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001480 {
daniel@transgaming.com4229f592011-11-24 22:34:04 +00001481 case 11: mUsesMod1 = true; break;
1482 case 22: mUsesMod2v = true; break;
1483 case 21: mUsesMod2f = true; break;
1484 case 33: mUsesMod3v = true; break;
1485 case 31: mUsesMod3f = true; break;
1486 case 44: mUsesMod4v = true; break;
1487 case 41: mUsesMod4f = true; break;
daniel@transgaming.comd7c98102010-05-14 17:30:48 +00001488 default: UNREACHABLE();
1489 }
1490
1491 outputTriplet(visit, "mod(", ", ", ")");
1492 }
1493 break;
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001494 case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001495 case EOpAtan:
daniel@transgaming.com0f189612010-05-07 13:03:36 +00001496 ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
1497 mUsesAtan2 = true;
1498 outputTriplet(visit, "atanyx(", ", ", ")");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001499 break;
1500 case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
1501 case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
1502 case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
1503 case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
1504 case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
1505 case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
1506 case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
1507 case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
1508 case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001509 case EOpFaceForward:
1510 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001511 switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
daniel@transgaming.com0bbb0312010-04-26 15:33:39 +00001512 {
1513 case 1: mUsesFaceforward1 = true; break;
1514 case 2: mUsesFaceforward2 = true; break;
1515 case 3: mUsesFaceforward3 = true; break;
1516 case 4: mUsesFaceforward4 = true; break;
1517 default: UNREACHABLE();
1518 }
1519
1520 outputTriplet(visit, "faceforward(", ", ", ")");
1521 }
1522 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001523 case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
1524 case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
1525 case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001526 default: UNREACHABLE();
1527 }
1528
1529 return true;
1530}
1531
1532bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1533{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001534 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001535
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001536 if (node->usesTernaryOperator())
1537 {
daniel@transgaming.comccb38412011-10-04 18:43:40 +00001538 out << "s" << mUnfoldSelect->getNextTemporaryIndex();
alokp@chromium.org60fe4072010-03-29 20:58:29 +00001539 }
1540 else // if/else statement
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001541 {
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001542 mUnfoldSelect->traverse(node->getCondition());
1543
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001544 out << "if(";
1545
1546 node->getCondition()->traverse(this);
1547
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001548 out << ")\n";
1549
1550 outputLineDirective(node->getLine());
1551 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552
daniel@transgaming.combb885322010-04-15 20:45:24 +00001553 if (node->getTrueBlock())
1554 {
1555 node->getTrueBlock()->traverse(this);
1556 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001558 outputLineDirective(node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 out << ";}\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001560
1561 if (node->getFalseBlock())
1562 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001563 out << "else\n";
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001564
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001565 outputLineDirective(node->getFalseBlock()->getLine());
1566 out << "{\n";
1567
1568 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001569 node->getFalseBlock()->traverse(this);
1570
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001571 outputLineDirective(node->getFalseBlock()->getLine());
daniel@transgaming.com3d53fda2010-03-21 04:30:55 +00001572 out << ";}\n";
1573 }
1574 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001575
1576 return false;
1577}
1578
1579void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1580{
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00001581 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001582}
1583
1584bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1585{
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001586 if (handleExcessiveLoop(node))
1587 {
1588 return false;
1589 }
1590
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001591 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001592
alokp@chromium.org52813552010-11-16 18:36:09 +00001593 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001594 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001595 out << "do\n";
1596
1597 outputLineDirective(node->getLine());
1598 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001599 }
1600 else
1601 {
1602 out << "for(";
1603
1604 if (node->getInit())
1605 {
1606 node->getInit()->traverse(this);
1607 }
1608
1609 out << "; ";
1610
alokp@chromium.org52813552010-11-16 18:36:09 +00001611 if (node->getCondition())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001612 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001613 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001614 }
1615
1616 out << "; ";
1617
alokp@chromium.org52813552010-11-16 18:36:09 +00001618 if (node->getExpression())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001620 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621 }
1622
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001623 out << ")\n";
1624
1625 outputLineDirective(node->getLine());
1626 out << "{\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001627 }
1628
1629 if (node->getBody())
1630 {
1631 node->getBody()->traverse(this);
1632 }
1633
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001634 outputLineDirective(node->getLine());
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00001635 out << ";}\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001636
alokp@chromium.org52813552010-11-16 18:36:09 +00001637 if (node->getType() == ELoopDoWhile)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001638 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001639 outputLineDirective(node->getCondition()->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 out << "while(\n";
1641
alokp@chromium.org52813552010-11-16 18:36:09 +00001642 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001643
1644 out << ")";
1645 }
1646
1647 out << ";\n";
1648
1649 return false;
1650}
1651
1652bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1653{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001654 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655
1656 switch (node->getFlowOp())
1657 {
apatrick@chromium.org05a5d8e2011-02-16 19:07:20 +00001658 case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
1659 case EOpBreak: outputTriplet(visit, "break;\n", "", ""); break;
1660 case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001661 case EOpReturn:
1662 if (visit == PreVisit)
1663 {
1664 if (node->getExpression())
1665 {
1666 out << "return ";
1667 }
1668 else
1669 {
1670 out << "return;\n";
1671 }
1672 }
1673 else if (visit == PostVisit)
1674 {
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001675 if (node->getExpression())
1676 {
1677 out << ";\n";
1678 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001679 }
1680 break;
1681 default: UNREACHABLE();
1682 }
1683
1684 return true;
1685}
1686
daniel@transgaming.comb5875982010-04-15 20:44:53 +00001687bool OutputHLSL::isSingleStatement(TIntermNode *node)
1688{
1689 TIntermAggregate *aggregate = node->getAsAggregate();
1690
1691 if (aggregate)
1692 {
1693 if (aggregate->getOp() == EOpSequence)
1694 {
1695 return false;
1696 }
1697 else
1698 {
1699 for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1700 {
1701 if (!isSingleStatement(*sit))
1702 {
1703 return false;
1704 }
1705 }
1706
1707 return true;
1708 }
1709 }
1710
1711 return true;
1712}
1713
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001714// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1715bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1716{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001717 TInfoSinkBase &out = mBody;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001718
1719 // Parse loops of the form:
1720 // for(int index = initial; index [comparator] limit; index += increment)
1721 TIntermSymbol *index = NULL;
1722 TOperator comparator = EOpNull;
1723 int initial = 0;
1724 int limit = 0;
1725 int increment = 0;
1726
1727 // Parse index name and intial value
1728 if (node->getInit())
1729 {
1730 TIntermAggregate *init = node->getInit()->getAsAggregate();
1731
1732 if (init)
1733 {
1734 TIntermSequence &sequence = init->getSequence();
1735 TIntermTyped *variable = sequence[0]->getAsTyped();
1736
1737 if (variable && variable->getQualifier() == EvqTemporary)
1738 {
1739 TIntermBinary *assign = variable->getAsBinaryNode();
1740
1741 if (assign->getOp() == EOpInitialize)
1742 {
1743 TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1744 TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1745
1746 if (symbol && constant)
1747 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001748 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001749 {
1750 index = symbol;
1751 initial = constant->getUnionArrayPointer()[0].getIConst();
1752 }
1753 }
1754 }
1755 }
1756 }
1757 }
1758
1759 // Parse comparator and limit value
alokp@chromium.org52813552010-11-16 18:36:09 +00001760 if (index != NULL && node->getCondition())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001761 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001762 TIntermBinary *test = node->getCondition()->getAsBinaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001763
1764 if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1765 {
1766 TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1767
1768 if (constant)
1769 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001770 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001771 {
1772 comparator = test->getOp();
1773 limit = constant->getUnionArrayPointer()[0].getIConst();
1774 }
1775 }
1776 }
1777 }
1778
1779 // Parse increment
alokp@chromium.org52813552010-11-16 18:36:09 +00001780 if (index != NULL && comparator != EOpNull && node->getExpression())
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001781 {
alokp@chromium.org52813552010-11-16 18:36:09 +00001782 TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
1783 TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001784
1785 if (binaryTerminal)
1786 {
1787 TOperator op = binaryTerminal->getOp();
1788 TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1789
1790 if (constant)
1791 {
alokp@chromium.org58e54292010-08-24 21:40:03 +00001792 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001793 {
1794 int value = constant->getUnionArrayPointer()[0].getIConst();
1795
1796 switch (op)
1797 {
1798 case EOpAddAssign: increment = value; break;
1799 case EOpSubAssign: increment = -value; break;
1800 default: UNIMPLEMENTED();
1801 }
1802 }
1803 }
1804 }
1805 else if (unaryTerminal)
1806 {
1807 TOperator op = unaryTerminal->getOp();
1808
1809 switch (op)
1810 {
1811 case EOpPostIncrement: increment = 1; break;
1812 case EOpPostDecrement: increment = -1; break;
1813 case EOpPreIncrement: increment = 1; break;
1814 case EOpPreDecrement: increment = -1; break;
1815 default: UNIMPLEMENTED();
1816 }
1817 }
1818 }
1819
1820 if (index != NULL && comparator != EOpNull && increment != 0)
1821 {
1822 if (comparator == EOpLessThanEqual)
1823 {
1824 comparator = EOpLessThan;
1825 limit += 1;
1826 }
1827
1828 if (comparator == EOpLessThan)
1829 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001830 int iterations = (limit - initial) / increment;
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001831
1832 if (iterations <= 255)
1833 {
1834 return false; // Not an excessive loop
1835 }
1836
1837 while (iterations > 0)
1838 {
daniel@transgaming.comf1f538e2011-02-09 16:30:01 +00001839 int clampedLimit = initial + increment * std::min(255, iterations);
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001840
1841 // for(int index = initial; index < clampedLimit; index += increment)
1842
1843 out << "for(int ";
1844 index->traverse(this);
1845 out << " = ";
1846 out << initial;
1847
1848 out << "; ";
1849 index->traverse(this);
1850 out << " < ";
1851 out << clampedLimit;
1852
1853 out << "; ";
1854 index->traverse(this);
1855 out << " += ";
1856 out << increment;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001857 out << ")\n";
1858
1859 outputLineDirective(node->getLine());
1860 out << "{\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001861
1862 if (node->getBody())
1863 {
1864 node->getBody()->traverse(this);
1865 }
1866
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001867 outputLineDirective(node->getLine());
daniel@transgaming.com7fb81e82011-09-23 18:20:46 +00001868 out << ";}\n";
daniel@transgaming.com4a35ef22010-04-08 03:51:06 +00001869
1870 initial += 255 * increment;
1871 iterations -= 255;
1872 }
1873
1874 return true;
1875 }
1876 else UNIMPLEMENTED();
1877 }
1878
1879 return false; // Not handled as an excessive loop
1880}
1881
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001882void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001883{
daniel@transgaming.com950f9932010-04-13 03:26:14 +00001884 TInfoSinkBase &out = mBody;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001885
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001886 if (visit == PreVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001887 {
1888 out << preString;
1889 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001890 else if (visit == InVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001891 {
1892 out << inString;
1893 }
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00001894 else if (visit == PostVisit)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001895 {
1896 out << postString;
1897 }
1898}
1899
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001900void OutputHLSL::outputLineDirective(int line)
1901{
1902 if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
1903 {
baustin@google.com8ab69842011-06-02 21:53:45 +00001904 mBody << "\n";
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +00001905 mBody << "#line " << line;
1906
1907 if (mContext.sourcePath)
1908 {
1909 mBody << " \"" << mContext.sourcePath << "\"";
1910 }
1911
1912 mBody << "\n";
1913 }
1914}
1915
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001916TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1917{
1918 TQualifier qualifier = symbol->getQualifier();
1919 const TType &type = symbol->getType();
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001920 TString name = symbol->getSymbol();
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001921
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001922 if (name.empty()) // HLSL demands named arguments, also for prototypes
1923 {
daniel@transgaming.comb6ef8f12010-11-15 16:41:14 +00001924 name = "x" + str(mUniqueIndex++);
daniel@transgaming.com005c7392010-04-15 20:45:27 +00001925 }
1926 else
1927 {
1928 name = decorate(name);
1929 }
1930
1931 return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
daniel@transgaming.comd1acd1e2010-04-13 03:25:57 +00001932}
1933
1934TString OutputHLSL::qualifierString(TQualifier qualifier)
1935{
1936 switch(qualifier)
1937 {
1938 case EvqIn: return "in";
1939 case EvqOut: return "out";
1940 case EvqInOut: return "inout";
1941 case EvqConstReadOnly: return "const";
1942 default: UNREACHABLE();
1943 }
1944
1945 return "";
1946}
1947
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001948TString OutputHLSL::typeString(const TType &type)
1949{
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001950 if (type.getBasicType() == EbtStruct)
1951 {
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001952 if (type.getTypeName() != "")
1953 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00001954 return structLookup(type.getTypeName());
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001955 }
daniel@transgaming.com6b998402010-05-04 03:35:07 +00001956 else // Nameless structure, define in place
daniel@transgaming.coma637e552010-04-29 03:39:08 +00001957 {
1958 const TTypeList &fields = *type.getStruct();
1959
1960 TString string = "struct\n"
1961 "{\n";
1962
1963 for (unsigned int i = 0; i < fields.size(); i++)
1964 {
1965 const TType &field = *fields[i].type;
1966
1967 string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1968 }
1969
1970 string += "} ";
1971
1972 return string;
1973 }
daniel@transgaming.comfe565152010-04-10 05:29:07 +00001974 }
1975 else if (type.isMatrix())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001976 {
1977 switch (type.getNominalSize())
1978 {
1979 case 2: return "float2x2";
1980 case 3: return "float3x3";
1981 case 4: return "float4x4";
1982 }
1983 }
1984 else
1985 {
1986 switch (type.getBasicType())
1987 {
1988 case EbtFloat:
1989 switch (type.getNominalSize())
1990 {
1991 case 1: return "float";
1992 case 2: return "float2";
1993 case 3: return "float3";
1994 case 4: return "float4";
1995 }
1996 case EbtInt:
1997 switch (type.getNominalSize())
1998 {
1999 case 1: return "int";
2000 case 2: return "int2";
2001 case 3: return "int3";
2002 case 4: return "int4";
2003 }
2004 case EbtBool:
2005 switch (type.getNominalSize())
2006 {
2007 case 1: return "bool";
2008 case 2: return "bool2";
2009 case 3: return "bool3";
2010 case 4: return "bool4";
2011 }
2012 case EbtVoid:
2013 return "void";
2014 case EbtSampler2D:
2015 return "sampler2D";
2016 case EbtSamplerCube:
2017 return "samplerCUBE";
apatrick@chromium.org65756022012-01-17 21:45:38 +00002018 case EbtSamplerExternalOES:
2019 return "sampler2D";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002020 }
2021 }
2022
2023 UNIMPLEMENTED(); // FIXME
2024 return "<unknown type>";
2025}
2026
2027TString OutputHLSL::arrayString(const TType &type)
2028{
2029 if (!type.isArray())
2030 {
2031 return "";
2032 }
2033
daniel@transgaming.com005c7392010-04-15 20:45:27 +00002034 return "[" + str(type.getArraySize()) + "]";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002035}
2036
2037TString OutputHLSL::initializer(const TType &type)
2038{
2039 TString string;
2040
daniel@transgaming.comead23042010-04-29 03:35:36 +00002041 for (int component = 0; component < type.getObjectSize(); component++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002042 {
daniel@transgaming.comead23042010-04-29 03:35:36 +00002043 string += "0";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002044
daniel@transgaming.comead23042010-04-29 03:35:36 +00002045 if (component < type.getObjectSize() - 1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002046 {
2047 string += ", ";
2048 }
2049 }
2050
daniel@transgaming.comead23042010-04-29 03:35:36 +00002051 return "{" + string + "}";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002052}
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002053
daniel@transgaming.com67de6d62010-04-29 03:35:30 +00002054void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
daniel@transgaming.com63691862010-04-29 03:32:42 +00002055{
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002056 if (name == "")
2057 {
daniel@transgaming.com6b998402010-05-04 03:35:07 +00002058 return; // Nameless structures don't have constructors
daniel@transgaming.coma637e552010-04-29 03:39:08 +00002059 }
2060
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002061 TType ctorType = type;
2062 ctorType.clearArrayness();
alokp@chromium.org58e54292010-08-24 21:40:03 +00002063 ctorType.setPrecision(EbpHigh);
2064 ctorType.setQualifier(EvqTemporary);
daniel@transgaming.com63691862010-04-29 03:32:42 +00002065
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002066 TString ctorName = type.getStruct() ? decorate(name) : name;
2067
2068 typedef std::vector<TType> ParameterArray;
2069 ParameterArray ctorParameters;
daniel@transgaming.com63691862010-04-29 03:32:42 +00002070
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002071 if (type.getStruct())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002072 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002073 mStructNames.insert(decorate(name));
2074
2075 TString structure;
2076 structure += "struct " + decorate(name) + "\n"
2077 "{\n";
2078
2079 const TTypeList &fields = *type.getStruct();
2080
2081 for (unsigned int i = 0; i < fields.size(); i++)
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002082 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002083 const TType &field = *fields[i].type;
2084
2085 structure += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002086 }
2087
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002088 structure += "};\n";
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002089
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002090 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002091 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002092 mStructDeclarations.push_back(structure);
2093 }
2094
2095 for (unsigned int i = 0; i < fields.size(); i++)
2096 {
2097 ctorParameters.push_back(*fields[i].type);
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002098 }
2099 }
daniel@transgaming.com55d48c72011-09-26 18:24:36 +00002100 else if (parameters)
2101 {
2102 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2103 {
2104 ctorParameters.push_back((*parameter)->getAsTyped()->getType());
2105 }
2106 }
daniel@transgaming.com7a7003c2010-04-29 03:35:33 +00002107 else UNREACHABLE();
daniel@transgaming.com63691862010-04-29 03:32:42 +00002108
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002109 TString constructor;
2110
2111 if (ctorType.getStruct())
2112 {
2113 constructor += ctorName + " " + ctorName + "_ctor(";
2114 }
2115 else // Built-in type
2116 {
2117 constructor += typeString(ctorType) + " " + ctorName + "(";
2118 }
2119
2120 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
2121 {
2122 const TType &type = ctorParameters[parameter];
2123
2124 constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2125
2126 if (parameter < ctorParameters.size() - 1)
2127 {
2128 constructor += ", ";
2129 }
2130 }
2131
2132 constructor += ")\n"
2133 "{\n";
2134
2135 if (ctorType.getStruct())
2136 {
2137 constructor += " " + ctorName + " structure = {";
2138 }
2139 else
2140 {
2141 constructor += " return " + typeString(ctorType) + "(";
2142 }
2143
2144 if (ctorType.isMatrix() && ctorParameters.size() == 1)
2145 {
2146 int dim = ctorType.getNominalSize();
2147 const TType &parameter = ctorParameters[0];
2148
2149 if (parameter.isScalar())
2150 {
2151 for (int row = 0; row < dim; row++)
2152 {
2153 for (int col = 0; col < dim; col++)
2154 {
2155 constructor += TString((row == col) ? "x0" : "0.0");
2156
2157 if (row < dim - 1 || col < dim - 1)
2158 {
2159 constructor += ", ";
2160 }
2161 }
2162 }
2163 }
2164 else if (parameter.isMatrix())
2165 {
2166 for (int row = 0; row < dim; row++)
2167 {
2168 for (int col = 0; col < dim; col++)
2169 {
2170 if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2171 {
2172 constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2173 }
2174 else
2175 {
2176 constructor += TString((row == col) ? "1.0" : "0.0");
2177 }
2178
2179 if (row < dim - 1 || col < dim - 1)
2180 {
2181 constructor += ", ";
2182 }
2183 }
2184 }
2185 }
2186 else UNREACHABLE();
2187 }
2188 else
2189 {
2190 int remainingComponents = ctorType.getObjectSize();
2191 int parameterIndex = 0;
2192
2193 while (remainingComponents > 0)
2194 {
2195 const TType &parameter = ctorParameters[parameterIndex];
2196 bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
2197
2198 constructor += "x" + str(parameterIndex);
2199
2200 if (parameter.isScalar())
2201 {
2202 remainingComponents -= parameter.getObjectSize();
2203 }
2204 else if (parameter.isVector())
2205 {
2206 if (remainingComponents == parameter.getObjectSize() || moreParameters)
2207 {
2208 remainingComponents -= parameter.getObjectSize();
2209 }
2210 else if (remainingComponents < parameter.getNominalSize())
2211 {
2212 switch (remainingComponents)
2213 {
2214 case 1: constructor += ".x"; break;
2215 case 2: constructor += ".xy"; break;
2216 case 3: constructor += ".xyz"; break;
2217 case 4: constructor += ".xyzw"; break;
2218 default: UNREACHABLE();
2219 }
2220
2221 remainingComponents = 0;
2222 }
2223 else UNREACHABLE();
2224 }
2225 else if (parameter.isMatrix() || parameter.getStruct())
2226 {
2227 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2228
2229 remainingComponents -= parameter.getObjectSize();
2230 }
2231 else UNREACHABLE();
2232
2233 if (moreParameters)
2234 {
2235 parameterIndex++;
2236 }
2237
2238 if (remainingComponents)
2239 {
2240 constructor += ", ";
2241 }
2242 }
2243 }
2244
2245 if (ctorType.getStruct())
2246 {
2247 constructor += "};\n"
2248 " return structure;\n"
2249 "}\n";
2250 }
2251 else
2252 {
2253 constructor += ");\n"
2254 "}\n";
2255 }
2256
daniel@transgaming.com63691862010-04-29 03:32:42 +00002257 mConstructors.insert(constructor);
2258}
2259
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002260const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2261{
2262 TInfoSinkBase &out = mBody;
2263
2264 if (type.getBasicType() == EbtStruct)
2265 {
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002266 out << structLookup(type.getTypeName()) + "_ctor(";
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002267
2268 const TTypeList *structure = type.getStruct();
2269
2270 for (size_t i = 0; i < structure->size(); i++)
2271 {
2272 const TType *fieldType = (*structure)[i].type;
2273
2274 constUnion = writeConstantUnion(*fieldType, constUnion);
2275
2276 if (i != structure->size() - 1)
2277 {
2278 out << ", ";
2279 }
2280 }
2281
2282 out << ")";
2283 }
2284 else
2285 {
2286 int size = type.getObjectSize();
2287 bool writeType = size > 1;
2288
2289 if (writeType)
2290 {
2291 out << typeString(type) << "(";
2292 }
2293
2294 for (int i = 0; i < size; i++, constUnion++)
2295 {
2296 switch (constUnion->getType())
2297 {
2298 case EbtFloat: out << constUnion->getFConst(); break;
2299 case EbtInt: out << constUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +00002300 case EbtBool: out << constUnion->getBConst(); break;
daniel@transgaming.coma54da4e2010-05-07 13:03:28 +00002301 default: UNREACHABLE();
2302 }
2303
2304 if (i != size - 1)
2305 {
2306 out << ", ";
2307 }
2308 }
2309
2310 if (writeType)
2311 {
2312 out << ")";
2313 }
2314 }
2315
2316 return constUnion;
2317}
2318
daniel@transgaming.coma2a95e72010-05-20 19:17:55 +00002319TString OutputHLSL::scopeString(unsigned int depthLimit)
2320{
2321 TString string;
2322
2323 for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2324 {
2325 string += "_" + str(i);
2326 }
2327
2328 return string;
2329}
2330
2331TString OutputHLSL::scopedStruct(const TString &typeName)
2332{
2333 if (typeName == "")
2334 {
2335 return typeName;
2336 }
2337
2338 return typeName + scopeString(mScopeDepth);
2339}
2340
2341TString OutputHLSL::structLookup(const TString &typeName)
2342{
2343 for (int depth = mScopeDepth; depth >= 0; depth--)
2344 {
2345 TString scopedName = decorate(typeName + scopeString(depth));
2346
2347 for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2348 {
2349 if (*structName == scopedName)
2350 {
2351 return scopedName;
2352 }
2353 }
2354 }
2355
2356 UNREACHABLE(); // Should have found a matching constructor
2357
2358 return typeName;
2359}
2360
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002361TString OutputHLSL::decorate(const TString &string)
2362{
daniel@transgaming.com51db7fb2011-09-20 16:11:06 +00002363 if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002364 {
2365 return "_" + string;
2366 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002367
2368 return string;
2369}
2370
apatrick@chromium.org65756022012-01-17 21:45:38 +00002371TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002372{
apatrick@chromium.org65756022012-01-17 21:45:38 +00002373 if (type.isArray())
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002374 {
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002375 return "ar_" + string; // Allows identifying arrays of size 1
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002376 }
apatrick@chromium.org65756022012-01-17 21:45:38 +00002377 else if (type.getBasicType() == EbtSamplerExternalOES)
2378 {
2379 return "ex_" + string;
2380 }
daniel@transgaming.comc72c6412011-09-20 16:09:17 +00002381
2382 return decorate(string);
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00002383}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002384}