blob: 4209b40470769420a025c03ced7b549e18615b53 [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;
alokp@chromium.org4e4facd2010-06-02 15:21:22 +0000186 case EbtBool: out << pConstUnion->getBConst(); break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000187 default: UNREACHABLE();
188 }
189 if (i != size - 1) out << ", ";
190 }
191 if (writeType) out << ")";
192 }
193 return pConstUnion;
194}
195
alokp@chromium.org76b82082010-03-24 17:59:39 +0000196void TOutputGLSL::visitSymbol(TIntermSymbol* node)
197{
198 TInfoSinkBase& out = objSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000199 out << node->getSymbol();
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000200
alokp@chromium.org194522f2010-05-06 19:09:26 +0000201 if (mDeclaringVariables && node->getType().isArray())
202 out << arrayBrackets(node->getType());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000203}
204
205void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
206{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000207 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000208}
209
210bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
211{
212 bool visitChildren = true;
213 TInfoSinkBase& out = objSink();
214 switch (node->getOp())
215 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000216 case EOpInitialize:
alokp@chromium.org194522f2010-05-06 19:09:26 +0000217 if (visit == InVisit)
218 {
alokp@chromium.org76b82082010-03-24 17:59:39 +0000219 out << " = ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000220 // RHS of initialize is not being declared.
221 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000222 }
223 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000224 case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000225 case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000226 case EOpSubAssign: writeTriplet(visit, NULL, " -= ", NULL); break;
227 case EOpDivAssign: writeTriplet(visit, NULL, " /= ", NULL); break;
228 case EOpMulAssign:
229 case EOpVectorTimesMatrixAssign:
230 case EOpVectorTimesScalarAssign:
231 case EOpMatrixTimesScalarAssign:
232 case EOpMatrixTimesMatrixAssign:
233 writeTriplet(visit, NULL, " *= ", NULL);
234 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000235
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000236 case EOpIndexDirect:
237 case EOpIndexIndirect:
238 writeTriplet(visit, NULL, "[", "]");
239 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000240 case EOpIndexDirectStruct:
241 if (visit == InVisit)
242 {
243 out << ".";
244 // TODO(alokp): ASSERT
245 out << node->getType().getFieldName();
246 visitChildren = false;
247 }
248 break;
249 case EOpVectorSwizzle:
250 if (visit == InVisit)
251 {
252 out << ".";
253 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
254 TIntermSequence& sequence = rightChild->getSequence();
255 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
256 {
257 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
258 ASSERT(element->getBasicType() == EbtInt);
259 ASSERT(element->getNominalSize() == 1);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000260 const ConstantUnion& data = element->getUnionArrayPointer()[0];
alokp@chromium.org76b82082010-03-24 17:59:39 +0000261 ASSERT(data.getType() == EbtInt);
262 switch (data.getIConst())
263 {
264 case 0: out << "x"; break;
265 case 1: out << "y"; break;
266 case 2: out << "z"; break;
267 case 3: out << "w"; break;
268 default: UNREACHABLE(); break;
269 }
270 }
271 visitChildren = false;
272 }
273 break;
274
275 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
276 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
277 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
278 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
279 case EOpMod: UNIMPLEMENTED(); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000280 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000281 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000282 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
alokp@chromium.orgdd037b22010-03-30 18:47:20 +0000283 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000284 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
285 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000286
287 // Notice the fall-through.
288 case EOpVectorTimesScalar:
289 case EOpVectorTimesMatrix:
290 case EOpMatrixTimesVector:
291 case EOpMatrixTimesScalar:
292 case EOpMatrixTimesMatrix:
293 writeTriplet(visit, "(", " * ", ")");
294 break;
295
296 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000297 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
298 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000299 default: UNREACHABLE(); break;
300 }
301
302 return visitChildren;
303}
304
305bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
306{
307 TInfoSinkBase& out = objSink();
308
309 switch (node->getOp())
310 {
311 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
alokp@chromium.org13b2dd82010-05-26 18:35:23 +0000312 case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000313 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000314
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000315 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
316 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
317 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
318 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000319
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000320 case EOpConvIntToBool:
321 case EOpConvFloatToBool:
322 switch (node->getOperand()->getType().getNominalSize())
323 {
324 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
325 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
326 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
327 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
328 default: UNREACHABLE();
329 }
330 break;
331 case EOpConvBoolToFloat:
332 case EOpConvIntToFloat:
333 switch (node->getOperand()->getType().getNominalSize())
334 {
335 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
336 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
337 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
338 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
339 default: UNREACHABLE();
340 }
341 break;
342 case EOpConvFloatToInt:
343 case EOpConvBoolToInt:
344 switch (node->getOperand()->getType().getNominalSize())
345 {
346 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
347 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
348 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
349 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
350 default: UNREACHABLE();
351 }
352 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000353
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000354 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
355 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000356 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
357 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000358 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
359 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
alokp@chromium.org3d270782010-03-30 20:33:38 +0000360 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000361 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000362
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000363 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
364 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
365 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
366 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
367 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
368 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000369
alokp@chromium.org3d270782010-03-30 20:33:38 +0000370 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000371 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000372 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000373 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
374 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000375
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000376 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000377 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
378
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000379 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
380 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000381
382 default: UNREACHABLE(); break;
383 }
384
385 return true;
386}
387
388bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
389{
390 TInfoSinkBase& out = objSink();
391
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000392 if (node->usesTernaryOperator())
alokp@chromium.org76b82082010-03-24 17:59:39 +0000393 {
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000394 out << "(";
395 node->getCondition()->traverse(this);
396 out << ") ? (";
397 node->getTrueBlock()->traverse(this);
398 out << ") : (";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000399 node->getFalseBlock()->traverse(this);
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000400 out << ")";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000401 }
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000402 else
403 {
404 out << "if (";
405 node->getCondition()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000406 out << ")\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000407
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000408 incrementDepth();
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000409 visitCodeBlock(node->getTrueBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000410
411 if (node->getFalseBlock())
412 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000413 out << "else\n";
414 visitCodeBlock(node->getFalseBlock());
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000415 }
416 decrementDepth();
alokp@chromium.org60fe4072010-03-29 20:58:29 +0000417 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000418 return false;
419}
420
421bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
422{
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000423 bool visitChildren = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000424 TInfoSinkBase& out = objSink();
425 switch (node->getOp())
426 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000427 case EOpSequence: {
428 // Scope the sequences except when at the global scope.
429 if (depth > 0) out << "{\n";
430
431 incrementDepth();
432 const TIntermSequence& sequence = node->getSequence();
433 for (TIntermSequence::const_iterator iter = sequence.begin();
434 iter != sequence.end(); ++iter)
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000435 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000436 TIntermNode* node = *iter;
437 ASSERT(node != NULL);
438 node->traverse(this);
439
440 if (isSingleStatement(node))
441 out << ";\n";
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000442 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000443 decrementDepth();
444
445 // Scope the sequences except when at the global scope.
446 if (depth > 0) out << "}\n";
447 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000448 break;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000449 }
alokp@chromium.org194522f2010-05-06 19:09:26 +0000450 case EOpPrototype: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000451 // Function declaration.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000452 ASSERT(visit == PreVisit);
453 TString returnType = getTypeName(node->getType());
454 out << returnType << " " << node->getName();
455
456 out << "(";
457 writeFunctionParameters(node->getSequence());
458 out << ")";
459
460 visitChildren = false;
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000461 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000462 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000463 case EOpFunction: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000464 // Function definition.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000465 ASSERT(visit == PreVisit);
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000466 TString returnType = getTypeName(node->getType());
467 TString functionName = TFunction::unmangleName(node->getName());
468 out << returnType << " " << functionName;
469
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000470 incrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000471 // Function definition node contains one or two children nodes
472 // representing function parameters and function body. The latter
473 // is not present in case of empty function bodies.
474 const TIntermSequence& sequence = node->getSequence();
475 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
476 TIntermSequence::const_iterator seqIter = sequence.begin();
477
478 // Traverse function parameters.
479 TIntermAggregate* params = (*seqIter)->getAsAggregate();
480 ASSERT(params != NULL);
481 ASSERT(params->getOp() == EOpParameters);
482 params->traverse(this);
483
484 // Traverse function body.
485 TIntermAggregate* body = ++seqIter != sequence.end() ?
486 (*seqIter)->getAsAggregate() : NULL;
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000487 visitCodeBlock(body);
488 decrementDepth();
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000489
490 // Fully processed; no need to visit children.
491 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000492 break;
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000493 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000494 case EOpFunctionCall:
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000495 // Function call.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000496 if (visit == PreVisit)
497 {
alokp@chromium.org43884872010-03-30 00:08:52 +0000498 TString functionName = TFunction::unmangleName(node->getName());
alokp@chromium.org76b82082010-03-24 17:59:39 +0000499 out << functionName << "(";
500 }
501 else if (visit == InVisit)
502 {
503 out << ", ";
504 }
505 else
506 {
507 out << ")";
508 }
509 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000510 case EOpParameters: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000511 // Function parameters.
alokp@chromium.org194522f2010-05-06 19:09:26 +0000512 ASSERT(visit == PreVisit);
513 out << "(";
514 writeFunctionParameters(node->getSequence());
515 out << ")";
516 visitChildren = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000517 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000518 }
519 case EOpDeclaration: {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000520 // Variable declaration.
alokp@chromium.org76b82082010-03-24 17:59:39 +0000521 if (visit == PreVisit)
522 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000523 const TIntermSequence& sequence = node->getSequence();
524 const TIntermTyped* variable = sequence.front()->getAsTyped();
525 writeVariableType(variable->getType());
526 out << " ";
527 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000528 }
529 else if (visit == InVisit)
530 {
531 out << ", ";
alokp@chromium.org194522f2010-05-06 19:09:26 +0000532 mDeclaringVariables = true;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000533 }
534 else
535 {
alokp@chromium.org194522f2010-05-06 19:09:26 +0000536 mDeclaringVariables = false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000537 }
538 break;
alokp@chromium.org194522f2010-05-06 19:09:26 +0000539 }
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000540 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
541 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
542 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
543 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
544 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
545 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
546 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
547 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
548 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
549 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
550 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
551 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
552 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
553 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
554 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000555 case EOpConstructStruct:
556 if (visit == PreVisit)
557 {
558 const TType& type = node->getType();
559 ASSERT(type.getBasicType() == EbtStruct);
560 out << type.getTypeName() << "(";
561 }
562 else if (visit == InVisit)
563 {
564 out << ", ";
565 }
566 else
567 {
568 out << ")";
569 }
570 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000571
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000572 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
573 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
574 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
575 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
576 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
577 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
578 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000579
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000580 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
581 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
582 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
583 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
584 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
585 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
586 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
587 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
588 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000589
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000590 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
591 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
592 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
593 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
594 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
595 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
596 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000597
598 default: UNREACHABLE(); break;
599 }
alokp@chromium.orgb3f7fb62010-05-05 18:21:51 +0000600 return visitChildren;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000601}
602
603bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
604{
alokp@chromium.org376e1062010-03-31 20:25:53 +0000605 TInfoSinkBase& out = objSink();
606
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000607 incrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000608 // Loop header.
609 if (node->testFirst()) // for loop
610 {
611 out << "for (";
612 if (node->getInit())
613 node->getInit()->traverse(this);
614 out << "; ";
615
616 ASSERT(node->getTest() != NULL);
617 node->getTest()->traverse(this);
618 out << "; ";
619
620 if (node->getTerminal())
621 node->getTerminal()->traverse(this);
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000622 out << ")\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000623 }
624 else // do-while loop
625 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000626 out << "do\n";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000627 }
628
629 // Loop body.
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000630 visitCodeBlock(node->getBody());
alokp@chromium.org376e1062010-03-31 20:25:53 +0000631
632 // Loop footer.
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000633 if (!node->testFirst()) // while loop
alokp@chromium.org376e1062010-03-31 20:25:53 +0000634 {
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000635 out << "while (";
alokp@chromium.org376e1062010-03-31 20:25:53 +0000636 ASSERT(node->getTest() != NULL);
637 node->getTest()->traverse(this);
638 out << ");\n";
639 }
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000640 decrementDepth();
alokp@chromium.org376e1062010-03-31 20:25:53 +0000641
642 // No need to visit children. They have been already processed in
643 // this function.
644 return false;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000645}
646
647bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
648{
649 TInfoSinkBase &out = objSink();
650
651 switch (node->getFlowOp())
652 {
alokp@chromium.org2986a8c2010-04-30 22:32:32 +0000653 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
654 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
655 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
alokp@chromium.orga499cfc2010-05-03 23:14:49 +0000656 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000657 default: UNREACHABLE(); break;
658 }
659
660 return true;
661}
alokp@chromium.orgd88b7732010-05-26 15:13:14 +0000662
663void TOutputGLSL::visitCodeBlock(TIntermNode* node) {
664 TInfoSinkBase &out = objSink();
665 if (node != NULL)
666 {
667 node->traverse(this);
668 // Single statements not part of a sequence need to be terminated
669 // with semi-colon.
670 if (isSingleStatement(node))
671 out << ";\n";
672 }
673 else
674 {
675 out << "{\n}\n"; // Empty code block.
676 }
677}