blob: 3224dfd374c42c8ee645de1f60fcfdd123c3bfec [file] [log] [blame]
alokp@chromium.org76b82082010-03-24 17:59:39 +00001//
zmo@google.com0b8d4eb2011-04-04 19:17:11 +00002// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org76b82082010-03-24 17:59:39 +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/OutputGLSL.h"
alokp@chromium.org91b72322010-06-02 15:50:56 +00008#include "compiler/debug.h"
alokp@chromium.org76b82082010-03-24 17:59:39 +00009
10namespace
11{
12TString getTypeName(const TType& type)
13{
14 TInfoSinkBase out;
15 if (type.isMatrix())
16 {
17 out << "mat";
18 out << type.getNominalSize();
19 }
alokp@chromium.org76b82082010-03-24 17:59:39 +000020 else if (type.isVector())
21 {
22 switch (type.getBasicType())
23 {
24 case EbtFloat: out << "vec"; break;
25 case EbtInt: out << "ivec"; break;
26 case EbtBool: out << "bvec"; break;
27 default: UNREACHABLE(); break;
28 }
29 out << type.getNominalSize();
30 }
31 else
32 {
33 if (type.getBasicType() == EbtStruct)
34 out << type.getTypeName();
35 else
36 out << type.getBasicString();
37 }
38 return TString(out.c_str());
39}
alokp@chromium.org194522f2010-05-06 19:09:26 +000040
41TString arrayBrackets(const TType& type)
42{
43 ASSERT(type.isArray());
44 TInfoSinkBase out;
45 out << "[" << type.getArraySize() << "]";
46 return TString(out.c_str());
47}
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000048
49bool isSingleStatement(TIntermNode* node) {
alokp@chromium.org334aa1f2010-06-11 23:38:29 +000050 if (const TIntermAggregate* aggregate = node->getAsAggregate())
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000051 {
alokp@chromium.org334aa1f2010-06-11 23:38:29 +000052 return (aggregate->getOp() != EOpFunction) &&
53 (aggregate->getOp() != EOpSequence);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000054 }
alokp@chromium.org334aa1f2010-06-11 23:38:29 +000055 else if (const TIntermSelection* selection = node->getAsSelectionNode())
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000056 {
alokp@chromium.org334aa1f2010-06-11 23:38:29 +000057 // Ternary operators are usually part of an assignment operator.
58 // This handles those rare cases in which they are all by themselves.
59 return selection->usesTernaryOperator();
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000060 }
alokp@chromium.org334aa1f2010-06-11 23:38:29 +000061 else if (node->getAsLoopNode())
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000062 {
63 return false;
64 }
65 return true;
66}
alokp@chromium.org76b82082010-03-24 17:59:39 +000067} // namespace
68
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000069TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
alokp@chromium.org76b82082010-03-24 17:59:39 +000070 : TIntermTraverser(true, true, true),
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000071 mObjSink(objSink),
alokp@chromium.org194522f2010-05-06 19:09:26 +000072 mDeclaringVariables(false)
alokp@chromium.org76b82082010-03-24 17:59:39 +000073{
74}
75
alokp@chromium.org76b82082010-03-24 17:59:39 +000076void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
77{
78 TInfoSinkBase& out = objSink();
79 if (visit == PreVisit && preStr)
80 {
81 out << preStr;
82 }
83 else if (visit == InVisit && inStr)
84 {
85 out << inStr;
86 }
87 else if (visit == PostVisit && postStr)
88 {
89 out << postStr;
90 }
91}
92
alokp@chromium.org194522f2010-05-06 19:09:26 +000093void TOutputGLSL::writeVariableType(const TType& type)
94{
95 TInfoSinkBase& out = objSink();
96 TQualifier qualifier = type.getQualifier();
97 // TODO(alokp): Validate qualifier for variable declarations.
98 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
99 out << type.getQualifierString() << " ";
100
101 // Declare the struct if we have not done so already.
102 if ((type.getBasicType() == EbtStruct) &&
103 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
104 {
105 out << "struct " << type.getTypeName() << "{\n";
106 const TTypeList* structure = type.getStruct();
107 ASSERT(structure != NULL);
108 for (size_t i = 0; i < structure->size(); ++i)
109 {
110 const TType* fieldType = (*structure)[i].type;
111 ASSERT(fieldType != NULL);
112 out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
113 if (fieldType->isArray())
114 out << arrayBrackets(*fieldType);
115 out << ";\n";
116 }
117 out << "}";
118 mDeclaredStructs.insert(type.getTypeName());
119 }
120 else
121 {
122 out << getTypeName(type);
123 }
124}
125
126void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args)
127{
128 TInfoSinkBase& out = objSink();
129 for (TIntermSequence::const_iterator iter = args.begin();
130 iter != args.end(); ++iter)
131 {
132 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
133 ASSERT(arg != NULL);
134
135 const TType& type = arg->getType();
136 TQualifier qualifier = type.getQualifier();
137 // TODO(alokp): Validate qualifier for function arguments.
138 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
139 out << type.getQualifierString() << " ";
140
141 out << getTypeName(type);
142
143 const TString& name = arg->getSymbol();
144 if (!name.empty())
145 out << " " << name;
146 if (type.isArray())
147 out << arrayBrackets(type);
148
149 // Put a comma if this is not the last argument.
alokp@chromium.org003e7b12010-08-09 17:14:46 +0000150 if (iter != args.end() - 1)
alokp@chromium.org194522f2010-05-06 19:09:26 +0000151 out << ", ";
152 }
153}
154
155const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type,
156 const ConstantUnion* pConstUnion)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000157{
158 TInfoSinkBase& out = objSink();
159
160 if (type.getBasicType() == EbtStruct)
161 {
162 out << type.getTypeName() << "(";
163 const TTypeList* structure = type.getStruct();
164 ASSERT(structure != NULL);
165 for (size_t i = 0; i < structure->size(); ++i)
166 {
167 const TType* fieldType = (*structure)[i].type;
168 ASSERT(fieldType != NULL);
169 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
170 if (i != structure->size() - 1) out << ", ";
171 }
172 out << ")";
173 }
174 else
175 {
176 int size = type.getObjectSize();
177 bool writeType = size > 1;
178 if (writeType) out << getTypeName(type) << "(";
179 for (int i = 0; i < size; ++i, ++pConstUnion)
180 {
181 switch (pConstUnion->getType())
182 {
183 case EbtFloat: out << pConstUnion->getFConst(); break;
184 case EbtInt: out << pConstUnion->getIConst(); break;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +0000185 case EbtBool: out << pConstUnion->getBConst(); break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000186 default: UNREACHABLE();
187 }
188 if (i != size - 1) out << ", ";
189 }
190 if (writeType) out << ")";
191 }
192 return pConstUnion;
193}
194
alokp@chromium.org76b82082010-03-24 17:59:39 +0000195void TOutputGLSL::visitSymbol(TIntermSymbol* node)
196{
197 TInfoSinkBase& out = objSink();
zmo@google.com0b8d4eb2011-04-04 19:17:11 +0000198 if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
199 out << mLoopUnroll.GetLoopIndexValue(node);
200 else
201 out << node->getSymbol();
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000202
alokp@chromium.org194522f2010-05-06 19:09:26 +0000203 if (mDeclaringVariables && node->getType().isArray())
204 out << arrayBrackets(node->getType());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000205}
206
207void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
208{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000209 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000210}
211
212bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
213{
214 bool visitChildren = true;
215 TInfoSinkBase& out = objSink();
216 switch (node->getOp())
217 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000218 case EOpInitialize:
alokp@chromium.org194522f2010-05-06 19:09:26 +0000219 if (visit == InVisit)
220 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000221 out << " = ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000222 // RHS of initialize is not being declared.
223 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000224 }
225 break;
alokp@chromium.orgcba04992010-06-14 20:36:41 +0000226 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
227 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
228 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
229 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
230 // Notice the fall-through.
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000231 case EOpMulAssign:
232 case EOpVectorTimesMatrixAssign:
233 case EOpVectorTimesScalarAssign:
234 case EOpMatrixTimesScalarAssign:
235 case EOpMatrixTimesMatrixAssign:
alokp@chromium.orgcba04992010-06-14 20:36:41 +0000236 writeTriplet(visit, "(", " *= ", ")");
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000237 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000238
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000239 case EOpIndexDirect:
240 case EOpIndexIndirect:
241 writeTriplet(visit, NULL, "[", "]");
242 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000243 case EOpIndexDirectStruct:
244 if (visit == InVisit)
245 {
246 out << ".";
247 // TODO(alokp): ASSERT
248 out << node->getType().getFieldName();
249 visitChildren = false;
250 }
251 break;
252 case EOpVectorSwizzle:
253 if (visit == InVisit)
254 {
255 out << ".";
256 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
257 TIntermSequence& sequence = rightChild->getSequence();
258 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
259 {
260 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
261 ASSERT(element->getBasicType() == EbtInt);
262 ASSERT(element->getNominalSize() == 1);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000263 const ConstantUnion& data = element->getUnionArrayPointer()[0];
alokp@chromium.org76b82082010-03-24 17:59:39 +0000264 ASSERT(data.getType() == EbtInt);
265 switch (data.getIConst())
266 {
267 case 0: out << "x"; break;
268 case 1: out << "y"; break;
269 case 2: out << "z"; break;
270 case 3: out << "w"; break;
271 default: UNREACHABLE(); break;
272 }
273 }
274 visitChildren = false;
275 }
276 break;
277
278 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
279 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
280 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
281 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
282 case EOpMod: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000283 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000284 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000285 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000286 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000287 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
288 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000289
290 // Notice the fall-through.
291 case EOpVectorTimesScalar:
292 case EOpVectorTimesMatrix:
293 case EOpMatrixTimesVector:
294 case EOpMatrixTimesScalar:
295 case EOpMatrixTimesMatrix:
296 writeTriplet(visit, "(", " * ", ")");
297 break;
298
299 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000300 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
301 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000302 default: UNREACHABLE(); break;
303 }
304
305 return visitChildren;
306}
307
308bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
309{
alokp@chromium.org76b82082010-03-24 17:59:39 +0000310 switch (node->getOp())
311 {
312 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
alokp@chromium.org13b2dd82010-05-26 18:35:23 +0000313 case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000314 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000315
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000316 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
317 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
318 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
319 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000320
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000321 case EOpConvIntToBool:
322 case EOpConvFloatToBool:
323 switch (node->getOperand()->getType().getNominalSize())
324 {
325 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
326 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
327 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
328 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
329 default: UNREACHABLE();
330 }
331 break;
332 case EOpConvBoolToFloat:
333 case EOpConvIntToFloat:
334 switch (node->getOperand()->getType().getNominalSize())
335 {
336 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
337 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
338 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
339 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
340 default: UNREACHABLE();
341 }
342 break;
343 case EOpConvFloatToInt:
344 case EOpConvBoolToInt:
345 switch (node->getOperand()->getType().getNominalSize())
346 {
347 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
348 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
349 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
350 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
351 default: UNREACHABLE();
352 }
353 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000354
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000355 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
356 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000357 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
358 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000359 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
360 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000361 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000362 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000363
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000364 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
365 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
366 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
367 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
368 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
369 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000370
alokp@chromium.org3d270782010-03-30 20:33:38 +0000371 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000372 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000373 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000374 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
375 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000376
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000377 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000378 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
379
alokp@chromium.org06098892010-08-26 19:36:42 +0000380 case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break;
381 case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break;
382 case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break;
383
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000384 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
385 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000386
387 default: UNREACHABLE(); break;
388 }
389
390 return true;
391}
392
393bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
394{
395 TInfoSinkBase& out = objSink();
396
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000397 if (node->usesTernaryOperator())
alokp@chromium.org76b82082010-03-24 17:59:39 +0000398 {
alokp@chromium.org5eb46092010-07-26 18:15:21 +0000399 // Notice two brackets at the beginning and end. The outer ones
400 // encapsulate the whole ternary expression. This preserves the
401 // order of precedence when ternary expressions are used in a
402 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
403 out << "((";
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000404 node->getCondition()->traverse(this);
405 out << ") ? (";
406 node->getTrueBlock()->traverse(this);
407 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000408 node->getFalseBlock()->traverse(this);
alokp@chromium.org5eb46092010-07-26 18:15:21 +0000409 out << "))";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000410 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000411 else
412 {
413 out << "if (";
414 node->getCondition()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000415 out << ")\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000416
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000417 incrementDepth();
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000418 visitCodeBlock(node->getTrueBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000419
420 if (node->getFalseBlock())
421 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000422 out << "else\n";
423 visitCodeBlock(node->getFalseBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000424 }
425 decrementDepth();
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000426 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000427 return false;
428}
429
430bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
431{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000432 bool visitChildren = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000433 TInfoSinkBase& out = objSink();
434 switch (node->getOp())
435 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000436 case EOpSequence: {
437 // Scope the sequences except when at the global scope.
438 if (depth > 0) out << "{\n";
439
440 incrementDepth();
441 const TIntermSequence& sequence = node->getSequence();
442 for (TIntermSequence::const_iterator iter = sequence.begin();
443 iter != sequence.end(); ++iter)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000444 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000445 TIntermNode* node = *iter;
446 ASSERT(node != NULL);
447 node->traverse(this);
448
449 if (isSingleStatement(node))
450 out << ";\n";
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000451 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000452 decrementDepth();
453
454 // Scope the sequences except when at the global scope.
455 if (depth > 0) out << "}\n";
456 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000457 break;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000458 }
alokp@chromium.org194522f2010-05-06 19:09:26 +0000459 case EOpPrototype: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000460 // Function declaration.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000461 ASSERT(visit == PreVisit);
462 TString returnType = getTypeName(node->getType());
463 out << returnType << " " << node->getName();
464
465 out << "(";
466 writeFunctionParameters(node->getSequence());
467 out << ")";
468
469 visitChildren = false;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000470 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000471 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000472 case EOpFunction: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000473 // Function definition.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000474 ASSERT(visit == PreVisit);
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000475 TString returnType = getTypeName(node->getType());
476 TString functionName = TFunction::unmangleName(node->getName());
477 out << returnType << " " << functionName;
478
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000479 incrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000480 // Function definition node contains one or two children nodes
481 // representing function parameters and function body. The latter
482 // is not present in case of empty function bodies.
483 const TIntermSequence& sequence = node->getSequence();
484 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
485 TIntermSequence::const_iterator seqIter = sequence.begin();
486
487 // Traverse function parameters.
488 TIntermAggregate* params = (*seqIter)->getAsAggregate();
489 ASSERT(params != NULL);
490 ASSERT(params->getOp() == EOpParameters);
491 params->traverse(this);
492
493 // Traverse function body.
494 TIntermAggregate* body = ++seqIter != sequence.end() ?
495 (*seqIter)->getAsAggregate() : NULL;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000496 visitCodeBlock(body);
497 decrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000498
499 // Fully processed; no need to visit children.
500 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000501 break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000502 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000503 case EOpFunctionCall:
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000504 // Function call.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000505 if (visit == PreVisit)
506 {
alokp@chromium.org43884872010-03-30 00:08:52 +0000507 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000508 out << functionName << "(";
509 }
510 else if (visit == InVisit)
511 {
512 out << ", ";
513 }
514 else
515 {
516 out << ")";
517 }
518 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000519 case EOpParameters: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000520 // Function parameters.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000521 ASSERT(visit == PreVisit);
522 out << "(";
523 writeFunctionParameters(node->getSequence());
524 out << ")";
525 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000526 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000527 }
528 case EOpDeclaration: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000529 // Variable declaration.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000530 if (visit == PreVisit)
531 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000532 const TIntermSequence& sequence = node->getSequence();
533 const TIntermTyped* variable = sequence.front()->getAsTyped();
534 writeVariableType(variable->getType());
535 out << " ";
536 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000537 }
538 else if (visit == InVisit)
539 {
540 out << ", ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000541 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000542 }
543 else
544 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000545 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000546 }
547 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000548 }
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000549 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
550 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
551 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
552 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
553 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
554 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
555 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
556 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
557 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
558 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
559 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
560 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
561 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
562 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
563 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000564 case EOpConstructStruct:
565 if (visit == PreVisit)
566 {
567 const TType& type = node->getType();
568 ASSERT(type.getBasicType() == EbtStruct);
569 out << type.getTypeName() << "(";
570 }
571 else if (visit == InVisit)
572 {
573 out << ", ";
574 }
575 else
576 {
577 out << ")";
578 }
579 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000580
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000581 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
582 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
583 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
584 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
585 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
586 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
587 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000588
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000589 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
590 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
591 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
592 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
593 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
594 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
595 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
596 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
597 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000598
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000599 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
600 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
601 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
602 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
603 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
604 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
605 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000606
607 default: UNREACHABLE(); break;
608 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000609 return visitChildren;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000610}
611
612bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
613{
alokp@chromium.org376e1062010-03-31 20:25:53 +0000614 TInfoSinkBase& out = objSink();
615
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000616 incrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000617 // Loop header.
alokp@chromium.org52813552010-11-16 18:36:09 +0000618 TLoopType loopType = node->getType();
619 if (loopType == ELoopFor) // for loop
alokp@chromium.org376e1062010-03-31 20:25:53 +0000620 {
zmo@google.com0b8d4eb2011-04-04 19:17:11 +0000621 if (!node->getUnrollFlag()) {
622 out << "for (";
623 if (node->getInit())
624 node->getInit()->traverse(this);
625 out << "; ";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000626
zmo@google.com0b8d4eb2011-04-04 19:17:11 +0000627 if (node->getCondition())
628 node->getCondition()->traverse(this);
629 out << "; ";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000630
zmo@google.com0b8d4eb2011-04-04 19:17:11 +0000631 if (node->getExpression())
632 node->getExpression()->traverse(this);
633 out << ")\n";
634 }
alokp@chromium.org52813552010-11-16 18:36:09 +0000635 }
636 else if (loopType == ELoopWhile) // while loop
637 {
638 out << "while (";
639 ASSERT(node->getCondition() != NULL);
640 node->getCondition()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000641 out << ")\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000642 }
643 else // do-while loop
644 {
alokp@chromium.org52813552010-11-16 18:36:09 +0000645 ASSERT(loopType == ELoopDoWhile);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000646 out << "do\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000647 }
648
649 // Loop body.
zmo@google.com0b8d4eb2011-04-04 19:17:11 +0000650 if (node->getUnrollFlag())
651 {
652 TLoopIndexInfo indexInfo;
653 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
654 mLoopUnroll.Push(indexInfo);
655 while (mLoopUnroll.SatisfiesLoopCondition())
656 {
657 visitCodeBlock(node->getBody());
658 mLoopUnroll.Step();
659 }
660 mLoopUnroll.Pop();
661 }
662 else
663 {
664 visitCodeBlock(node->getBody());
665 }
alokp@chromium.org376e1062010-03-31 20:25:53 +0000666
667 // Loop footer.
alokp@chromium.org52813552010-11-16 18:36:09 +0000668 if (loopType == ELoopDoWhile) // do-while loop
alokp@chromium.org376e1062010-03-31 20:25:53 +0000669 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000670 out << "while (";
alokp@chromium.org52813552010-11-16 18:36:09 +0000671 ASSERT(node->getCondition() != NULL);
672 node->getCondition()->traverse(this);
alokp@chromium.org376e1062010-03-31 20:25:53 +0000673 out << ");\n";
674 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000675 decrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000676
677 // No need to visit children. They have been already processed in
678 // this function.
679 return false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000680}
681
682bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
683{
alokp@chromium.org76b82082010-03-24 17:59:39 +0000684 switch (node->getFlowOp())
685 {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000686 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
687 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
688 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000689 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000690 default: UNREACHABLE(); break;
691 }
692
693 return true;
694}
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000695
696void TOutputGLSL::visitCodeBlock(TIntermNode* node) {
697 TInfoSinkBase &out = objSink();
698 if (node != NULL)
699 {
700 node->traverse(this);
701 // Single statements not part of a sequence need to be terminated
702 // with semi-colon.
703 if (isSingleStatement(node))
704 out << ";\n";
705 }
706 else
707 {
708 out << "{\n}\n"; // Empty code block.
709 }
710}