blob: 1b3c13a14419b9cc0f57dbebb8ad71e0e9b81a0c [file] [log] [blame]
alokp@chromium.org76b82082010-03-24 17:59:39 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.combbf56f72010-04-20 18:52:13 +00007#include "compiler/OutputGLSL.h"
8
alokp@chromium.org76b82082010-03-24 17:59:39 +00009#include "common/debug.h"
10
11namespace
12{
13TString getTypeName(const TType& type)
14{
15 TInfoSinkBase out;
16 if (type.isMatrix())
17 {
18 out << "mat";
19 out << type.getNominalSize();
20 }
alokp@chromium.org76b82082010-03-24 17:59:39 +000021 else if (type.isVector())
22 {
23 switch (type.getBasicType())
24 {
25 case EbtFloat: out << "vec"; break;
26 case EbtInt: out << "ivec"; break;
27 case EbtBool: out << "bvec"; break;
28 default: UNREACHABLE(); break;
29 }
30 out << type.getNominalSize();
31 }
32 else
33 {
34 if (type.getBasicType() == EbtStruct)
35 out << type.getTypeName();
36 else
37 out << type.getBasicString();
38 }
39 return TString(out.c_str());
40}
alokp@chromium.org194522f2010-05-06 19:09:26 +000041
42TString arrayBrackets(const TType& type)
43{
44 ASSERT(type.isArray());
45 TInfoSinkBase out;
46 out << "[" << type.getArraySize() << "]";
47 return TString(out.c_str());
48}
alokp@chromium.orgd88b7732010-05-26 15:13:14 +000049
50bool isSingleStatement(TIntermNode* node) {
51 const TIntermAggregate* aggregate = node->getAsAggregate();
52 if (aggregate != NULL)
53 {
54 if ((aggregate->getOp() == EOpFunction) ||
55 (aggregate->getOp() == EOpSequence))
56 return false;
57 }
58 else if (node->getAsSelectionNode() != NULL)
59 {
60 return false;
61 }
62 else if (node->getAsLoopNode() != NULL)
63 {
64 return false;
65 }
66 return true;
67}
alokp@chromium.org76b82082010-03-24 17:59:39 +000068} // namespace
69
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000070TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
alokp@chromium.org76b82082010-03-24 17:59:39 +000071 : TIntermTraverser(true, true, true),
alokp@chromium.orga499cfc2010-05-03 23:14:49 +000072 mObjSink(objSink),
alokp@chromium.org194522f2010-05-06 19:09:26 +000073 mDeclaringVariables(false)
alokp@chromium.org76b82082010-03-24 17:59:39 +000074{
75}
76
alokp@chromium.org76b82082010-03-24 17:59:39 +000077void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
78{
79 TInfoSinkBase& out = objSink();
80 if (visit == PreVisit && preStr)
81 {
82 out << preStr;
83 }
84 else if (visit == InVisit && inStr)
85 {
86 out << inStr;
87 }
88 else if (visit == PostVisit && postStr)
89 {
90 out << postStr;
91 }
92}
93
alokp@chromium.org194522f2010-05-06 19:09:26 +000094void TOutputGLSL::writeVariableType(const TType& type)
95{
96 TInfoSinkBase& out = objSink();
97 TQualifier qualifier = type.getQualifier();
98 // TODO(alokp): Validate qualifier for variable declarations.
99 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
100 out << type.getQualifierString() << " ";
101
102 // Declare the struct if we have not done so already.
103 if ((type.getBasicType() == EbtStruct) &&
104 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
105 {
106 out << "struct " << type.getTypeName() << "{\n";
107 const TTypeList* structure = type.getStruct();
108 ASSERT(structure != NULL);
109 for (size_t i = 0; i < structure->size(); ++i)
110 {
111 const TType* fieldType = (*structure)[i].type;
112 ASSERT(fieldType != NULL);
113 out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
114 if (fieldType->isArray())
115 out << arrayBrackets(*fieldType);
116 out << ";\n";
117 }
118 out << "}";
119 mDeclaredStructs.insert(type.getTypeName());
120 }
121 else
122 {
123 out << getTypeName(type);
124 }
125}
126
127void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args)
128{
129 TInfoSinkBase& out = objSink();
130 for (TIntermSequence::const_iterator iter = args.begin();
131 iter != args.end(); ++iter)
132 {
133 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
134 ASSERT(arg != NULL);
135
136 const TType& type = arg->getType();
137 TQualifier qualifier = type.getQualifier();
138 // TODO(alokp): Validate qualifier for function arguments.
139 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
140 out << type.getQualifierString() << " ";
141
142 out << getTypeName(type);
143
144 const TString& name = arg->getSymbol();
145 if (!name.empty())
146 out << " " << name;
147 if (type.isArray())
148 out << arrayBrackets(type);
149
150 // Put a comma if this is not the last argument.
151 if (iter != --args.end())
152 out << ", ";
153 }
154}
155
156const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type,
157 const ConstantUnion* pConstUnion)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000158{
159 TInfoSinkBase& out = objSink();
160
161 if (type.getBasicType() == EbtStruct)
162 {
163 out << type.getTypeName() << "(";
164 const TTypeList* structure = type.getStruct();
165 ASSERT(structure != NULL);
166 for (size_t i = 0; i < structure->size(); ++i)
167 {
168 const TType* fieldType = (*structure)[i].type;
169 ASSERT(fieldType != NULL);
170 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
171 if (i != structure->size() - 1) out << ", ";
172 }
173 out << ")";
174 }
175 else
176 {
177 int size = type.getObjectSize();
178 bool writeType = size > 1;
179 if (writeType) out << getTypeName(type) << "(";
180 for (int i = 0; i < size; ++i, ++pConstUnion)
181 {
182 switch (pConstUnion->getType())
183 {
184 case EbtFloat: out << pConstUnion->getFConst(); break;
185 case EbtInt: out << pConstUnion->getIConst(); break;
186 case EbtBool:
187 if (pConstUnion->getBConst())
188 out << "true";
189 else
190 out << "false";
191 break;
192 default: UNREACHABLE();
193 }
194 if (i != size - 1) out << ", ";
195 }
196 if (writeType) out << ")";
197 }
198 return pConstUnion;
199}
200
alokp@chromium.org76b82082010-03-24 17:59:39 +0000201void TOutputGLSL::visitSymbol(TIntermSymbol* node)
202{
203 TInfoSinkBase& out = objSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000204 out << node->getSymbol();
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000205
alokp@chromium.org194522f2010-05-06 19:09:26 +0000206 if (mDeclaringVariables && node->getType().isArray())
207 out << arrayBrackets(node->getType());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000208}
209
210void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
211{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000212 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000213}
214
215bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
216{
217 bool visitChildren = true;
218 TInfoSinkBase& out = objSink();
219 switch (node->getOp())
220 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000221 case EOpInitialize:
alokp@chromium.org194522f2010-05-06 19:09:26 +0000222 if (visit == InVisit)
223 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000224 out << " = ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000225 // RHS of initialize is not being declared.
226 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000227 }
228 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000229 case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000230 case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000231 case EOpSubAssign: writeTriplet(visit, NULL, " -= ", NULL); break;
232 case EOpDivAssign: writeTriplet(visit, NULL, " /= ", NULL); break;
233 case EOpMulAssign:
234 case EOpVectorTimesMatrixAssign:
235 case EOpVectorTimesScalarAssign:
236 case EOpMatrixTimesScalarAssign:
237 case EOpMatrixTimesMatrixAssign:
238 writeTriplet(visit, NULL, " *= ", NULL);
239 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000240
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000241 case EOpIndexDirect:
242 case EOpIndexIndirect:
243 writeTriplet(visit, NULL, "[", "]");
244 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000245 case EOpIndexDirectStruct:
246 if (visit == InVisit)
247 {
248 out << ".";
249 // TODO(alokp): ASSERT
250 out << node->getType().getFieldName();
251 visitChildren = false;
252 }
253 break;
254 case EOpVectorSwizzle:
255 if (visit == InVisit)
256 {
257 out << ".";
258 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
259 TIntermSequence& sequence = rightChild->getSequence();
260 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
261 {
262 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
263 ASSERT(element->getBasicType() == EbtInt);
264 ASSERT(element->getNominalSize() == 1);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000265 const ConstantUnion& data = element->getUnionArrayPointer()[0];
alokp@chromium.org76b82082010-03-24 17:59:39 +0000266 ASSERT(data.getType() == EbtInt);
267 switch (data.getIConst())
268 {
269 case 0: out << "x"; break;
270 case 1: out << "y"; break;
271 case 2: out << "z"; break;
272 case 3: out << "w"; break;
273 default: UNREACHABLE(); break;
274 }
275 }
276 visitChildren = false;
277 }
278 break;
279
280 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
281 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
282 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
283 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
284 case EOpMod: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000285 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000286 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000287 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000288 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000289 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
290 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000291
292 // Notice the fall-through.
293 case EOpVectorTimesScalar:
294 case EOpVectorTimesMatrix:
295 case EOpMatrixTimesVector:
296 case EOpMatrixTimesScalar:
297 case EOpMatrixTimesMatrix:
298 writeTriplet(visit, "(", " * ", ")");
299 break;
300
301 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000302 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
303 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000304 default: UNREACHABLE(); break;
305 }
306
307 return visitChildren;
308}
309
310bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
311{
312 TInfoSinkBase& out = objSink();
313
314 switch (node->getOp())
315 {
316 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000317 case EOpVectorLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
318 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000319
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000320 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
321 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
322 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
323 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000324
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000325 case EOpConvIntToBool:
326 case EOpConvFloatToBool:
327 switch (node->getOperand()->getType().getNominalSize())
328 {
329 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
330 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
331 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
332 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
333 default: UNREACHABLE();
334 }
335 break;
336 case EOpConvBoolToFloat:
337 case EOpConvIntToFloat:
338 switch (node->getOperand()->getType().getNominalSize())
339 {
340 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
341 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
342 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
343 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
344 default: UNREACHABLE();
345 }
346 break;
347 case EOpConvFloatToInt:
348 case EOpConvBoolToInt:
349 switch (node->getOperand()->getType().getNominalSize())
350 {
351 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
352 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
353 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
354 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
355 default: UNREACHABLE();
356 }
357 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000358
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000359 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
360 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000361 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
362 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000363 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
364 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000365 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000366 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000367
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000368 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
369 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
370 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
371 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
372 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
373 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000374
alokp@chromium.org3d270782010-03-30 20:33:38 +0000375 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000376 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000377 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000378 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
379 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000380
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000381 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000382 case EOpNormalize: writeTriplet(visit, "normalize(", 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.org60fe4072010-03-29 20:58:29 +0000399 out << "(";
400 node->getCondition()->traverse(this);
401 out << ") ? (";
402 node->getTrueBlock()->traverse(this);
403 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000404 node->getFalseBlock()->traverse(this);
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000405 out << ")";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000406 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000407 else
408 {
409 out << "if (";
410 node->getCondition()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000411 out << ")\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000412
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000413 incrementDepth();
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000414 visitCodeBlock(node->getTrueBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000415
416 if (node->getFalseBlock())
417 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000418 out << "else\n";
419 visitCodeBlock(node->getFalseBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000420 }
421 decrementDepth();
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000422 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000423 return false;
424}
425
426bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
427{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000428 bool visitChildren = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000429 TInfoSinkBase& out = objSink();
430 switch (node->getOp())
431 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000432 case EOpSequence: {
433 // Scope the sequences except when at the global scope.
434 if (depth > 0) out << "{\n";
435
436 incrementDepth();
437 const TIntermSequence& sequence = node->getSequence();
438 for (TIntermSequence::const_iterator iter = sequence.begin();
439 iter != sequence.end(); ++iter)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000440 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000441 TIntermNode* node = *iter;
442 ASSERT(node != NULL);
443 node->traverse(this);
444
445 if (isSingleStatement(node))
446 out << ";\n";
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000447 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000448 decrementDepth();
449
450 // Scope the sequences except when at the global scope.
451 if (depth > 0) out << "}\n";
452 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000453 break;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000454 }
alokp@chromium.org194522f2010-05-06 19:09:26 +0000455 case EOpPrototype: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000456 // Function declaration.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000457 ASSERT(visit == PreVisit);
458 TString returnType = getTypeName(node->getType());
459 out << returnType << " " << node->getName();
460
461 out << "(";
462 writeFunctionParameters(node->getSequence());
463 out << ")";
464
465 visitChildren = false;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000466 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000467 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000468 case EOpFunction: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000469 // Function definition.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000470 ASSERT(visit == PreVisit);
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000471 TString returnType = getTypeName(node->getType());
472 TString functionName = TFunction::unmangleName(node->getName());
473 out << returnType << " " << functionName;
474
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000475 incrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000476 // Function definition node contains one or two children nodes
477 // representing function parameters and function body. The latter
478 // is not present in case of empty function bodies.
479 const TIntermSequence& sequence = node->getSequence();
480 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
481 TIntermSequence::const_iterator seqIter = sequence.begin();
482
483 // Traverse function parameters.
484 TIntermAggregate* params = (*seqIter)->getAsAggregate();
485 ASSERT(params != NULL);
486 ASSERT(params->getOp() == EOpParameters);
487 params->traverse(this);
488
489 // Traverse function body.
490 TIntermAggregate* body = ++seqIter != sequence.end() ?
491 (*seqIter)->getAsAggregate() : NULL;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000492 visitCodeBlock(body);
493 decrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000494
495 // Fully processed; no need to visit children.
496 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000497 break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000498 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000499 case EOpFunctionCall:
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000500 // Function call.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000501 if (visit == PreVisit)
502 {
alokp@chromium.org43884872010-03-30 00:08:52 +0000503 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000504 out << functionName << "(";
505 }
506 else if (visit == InVisit)
507 {
508 out << ", ";
509 }
510 else
511 {
512 out << ")";
513 }
514 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000515 case EOpParameters: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000516 // Function parameters.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000517 ASSERT(visit == PreVisit);
518 out << "(";
519 writeFunctionParameters(node->getSequence());
520 out << ")";
521 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000522 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000523 }
524 case EOpDeclaration: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000525 // Variable declaration.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000526 if (visit == PreVisit)
527 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000528 const TIntermSequence& sequence = node->getSequence();
529 const TIntermTyped* variable = sequence.front()->getAsTyped();
530 writeVariableType(variable->getType());
531 out << " ";
532 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000533 }
534 else if (visit == InVisit)
535 {
536 out << ", ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000537 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000538 }
539 else
540 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000541 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000542 }
543 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000544 }
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000545 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
546 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
547 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
548 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
549 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
550 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
551 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
552 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
553 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
554 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
555 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
556 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
557 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
558 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
559 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000560 case EOpConstructStruct:
561 if (visit == PreVisit)
562 {
563 const TType& type = node->getType();
564 ASSERT(type.getBasicType() == EbtStruct);
565 out << type.getTypeName() << "(";
566 }
567 else if (visit == InVisit)
568 {
569 out << ", ";
570 }
571 else
572 {
573 out << ")";
574 }
575 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000576
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000577 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
578 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
579 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
580 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
581 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
582 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
583 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000584
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000585 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
586 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
587 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
588 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
589 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
590 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
591 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
592 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
593 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000594
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000595 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
596 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
597 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
598 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
599 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
600 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
601 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000602
603 default: UNREACHABLE(); break;
604 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000605 return visitChildren;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000606}
607
608bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
609{
alokp@chromium.org376e1062010-03-31 20:25:53 +0000610 TInfoSinkBase& out = objSink();
611
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000612 incrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000613 // Loop header.
614 if (node->testFirst()) // for loop
615 {
616 out << "for (";
617 if (node->getInit())
618 node->getInit()->traverse(this);
619 out << "; ";
620
621 ASSERT(node->getTest() != NULL);
622 node->getTest()->traverse(this);
623 out << "; ";
624
625 if (node->getTerminal())
626 node->getTerminal()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000627 out << ")\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000628 }
629 else // do-while loop
630 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000631 out << "do\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000632 }
633
634 // Loop body.
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000635 visitCodeBlock(node->getBody());
alokp@chromium.org376e1062010-03-31 20:25:53 +0000636
637 // Loop footer.
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000638 if (!node->testFirst()) // while loop
alokp@chromium.org376e1062010-03-31 20:25:53 +0000639 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000640 out << "while (";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000641 ASSERT(node->getTest() != NULL);
642 node->getTest()->traverse(this);
643 out << ");\n";
644 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000645 decrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000646
647 // No need to visit children. They have been already processed in
648 // this function.
649 return false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000650}
651
652bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
653{
654 TInfoSinkBase &out = objSink();
655
656 switch (node->getFlowOp())
657 {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000658 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
659 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
660 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000661 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000662 default: UNREACHABLE(); break;
663 }
664
665 return true;
666}
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000667
668void TOutputGLSL::visitCodeBlock(TIntermNode* node) {
669 TInfoSinkBase &out = objSink();
670 if (node != NULL)
671 {
672 node->traverse(this);
673 // Single statements not part of a sequence need to be terminated
674 // with semi-colon.
675 if (isSingleStatement(node))
676 out << ";\n";
677 }
678 else
679 {
680 out << "{\n}\n"; // Empty code block.
681 }
682}