1 //
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
7 #include "compiler/OutputGLSL.h"
8 #include "compiler/debug.h"
9
10 namespace
11 {
getTypeName(const TType & type)12 TString getTypeName(const TType& type)
13 {
14 TInfoSinkBase out;
15 if (type.isMatrix())
16 {
17 out << "mat";
18 out << type.getNominalSize();
19 }
20 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 }
40
arrayBrackets(const TType & type)41 TString arrayBrackets(const TType& type)
42 {
43 ASSERT(type.isArray());
44 TInfoSinkBase out;
45 out << "[" << type.getArraySize() << "]";
46 return TString(out.c_str());
47 }
48
isSingleStatement(TIntermNode * node)49 bool isSingleStatement(TIntermNode* node) {
50 if (const TIntermAggregate* aggregate = node->getAsAggregate())
51 {
52 return (aggregate->getOp() != EOpFunction) &&
53 (aggregate->getOp() != EOpSequence);
54 }
55 else if (const TIntermSelection* selection = node->getAsSelectionNode())
56 {
57 // 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();
60 }
61 else if (node->getAsLoopNode())
62 {
63 return false;
64 }
65 return true;
66 }
67 } // namespace
68
TOutputGLSL(TInfoSinkBase & objSink)69 TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
70 : TIntermTraverser(true, true, true),
71 mObjSink(objSink),
72 mDeclaringVariables(false)
73 {
74 }
75
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)76 void 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
writeVariableType(const TType & type)93 void 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
writeFunctionParameters(const TIntermSequence & args)126 void 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.
150 if (iter != args.end() - 1)
151 out << ", ";
152 }
153 }
154
writeConstantUnion(const TType & type,const ConstantUnion * pConstUnion)155 const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type,
156 const ConstantUnion* pConstUnion)
157 {
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;
185 case EbtBool: out << pConstUnion->getBConst(); break;
186 default: UNREACHABLE();
187 }
188 if (i != size - 1) out << ", ";
189 }
190 if (writeType) out << ")";
191 }
192 return pConstUnion;
193 }
194
visitSymbol(TIntermSymbol * node)195 void TOutputGLSL::visitSymbol(TIntermSymbol* node)
196 {
197 TInfoSinkBase& out = objSink();
198 out << node->getSymbol();
199
200 if (mDeclaringVariables && node->getType().isArray())
201 out << arrayBrackets(node->getType());
202 }
203
visitConstantUnion(TIntermConstantUnion * node)204 void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
205 {
206 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
207 }
208
visitBinary(Visit visit,TIntermBinary * node)209 bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
210 {
211 bool visitChildren = true;
212 TInfoSinkBase& out = objSink();
213 switch (node->getOp())
214 {
215 case EOpInitialize:
216 if (visit == InVisit)
217 {
218 out << " = ";
219 // RHS of initialize is not being declared.
220 mDeclaringVariables = false;
221 }
222 break;
223 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
224 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
225 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
226 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
227 // Notice the fall-through.
228 case EOpMulAssign:
229 case EOpVectorTimesMatrixAssign:
230 case EOpVectorTimesScalarAssign:
231 case EOpMatrixTimesScalarAssign:
232 case EOpMatrixTimesMatrixAssign:
233 writeTriplet(visit, "(", " *= ", ")");
234 break;
235
236 case EOpIndexDirect:
237 case EOpIndexIndirect:
238 writeTriplet(visit, NULL, "[", "]");
239 break;
240 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);
260 const ConstantUnion& data = element->getUnionArrayPointer()[0];
261 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;
280 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
281 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
282 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
283 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
284 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
285 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
286
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;
297 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
298 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
299 default: UNREACHABLE(); break;
300 }
301
302 return visitChildren;
303 }
304
visitUnary(Visit visit,TIntermUnary * node)305 bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
306 {
307 switch (node->getOp())
308 {
309 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
310 case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
311 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
312
313 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
314 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
315 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
316 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
317
318 case EOpConvIntToBool:
319 case EOpConvFloatToBool:
320 switch (node->getOperand()->getType().getNominalSize())
321 {
322 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
323 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
324 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
325 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
326 default: UNREACHABLE();
327 }
328 break;
329 case EOpConvBoolToFloat:
330 case EOpConvIntToFloat:
331 switch (node->getOperand()->getType().getNominalSize())
332 {
333 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
334 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
335 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
336 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
337 default: UNREACHABLE();
338 }
339 break;
340 case EOpConvFloatToInt:
341 case EOpConvBoolToInt:
342 switch (node->getOperand()->getType().getNominalSize())
343 {
344 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
345 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
346 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
347 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
348 default: UNREACHABLE();
349 }
350 break;
351
352 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
353 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
354 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
355 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
356 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
357 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
358 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
359 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
360
361 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
362 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
363 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
364 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
365 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
366 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
367
368 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
369 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
370 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
371 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
372 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
373
374 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
375 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
376
377 case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break;
378 case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break;
379 case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break;
380
381 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
382 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
383
384 default: UNREACHABLE(); break;
385 }
386
387 return true;
388 }
389
visitSelection(Visit visit,TIntermSelection * node)390 bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
391 {
392 TInfoSinkBase& out = objSink();
393
394 if (node->usesTernaryOperator())
395 {
396 // Notice two brackets at the beginning and end. The outer ones
397 // encapsulate the whole ternary expression. This preserves the
398 // order of precedence when ternary expressions are used in a
399 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
400 out << "((";
401 node->getCondition()->traverse(this);
402 out << ") ? (";
403 node->getTrueBlock()->traverse(this);
404 out << ") : (";
405 node->getFalseBlock()->traverse(this);
406 out << "))";
407 }
408 else
409 {
410 out << "if (";
411 node->getCondition()->traverse(this);
412 out << ")\n";
413
414 incrementDepth();
415 visitCodeBlock(node->getTrueBlock());
416
417 if (node->getFalseBlock())
418 {
419 out << "else\n";
420 visitCodeBlock(node->getFalseBlock());
421 }
422 decrementDepth();
423 }
424 return false;
425 }
426
visitAggregate(Visit visit,TIntermAggregate * node)427 bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
428 {
429 bool visitChildren = true;
430 TInfoSinkBase& out = objSink();
431 switch (node->getOp())
432 {
433 case EOpSequence: {
434 // Scope the sequences except when at the global scope.
435 if (depth > 0) out << "{\n";
436
437 incrementDepth();
438 const TIntermSequence& sequence = node->getSequence();
439 for (TIntermSequence::const_iterator iter = sequence.begin();
440 iter != sequence.end(); ++iter)
441 {
442 TIntermNode* node = *iter;
443 ASSERT(node != NULL);
444 node->traverse(this);
445
446 if (isSingleStatement(node))
447 out << ";\n";
448 }
449 decrementDepth();
450
451 // Scope the sequences except when at the global scope.
452 if (depth > 0) out << "}\n";
453 visitChildren = false;
454 break;
455 }
456 case EOpPrototype: {
457 // Function declaration.
458 ASSERT(visit == PreVisit);
459 TString returnType = getTypeName(node->getType());
460 out << returnType << " " << node->getName();
461
462 out << "(";
463 writeFunctionParameters(node->getSequence());
464 out << ")";
465
466 visitChildren = false;
467 break;
468 }
469 case EOpFunction: {
470 // Function definition.
471 ASSERT(visit == PreVisit);
472 TString returnType = getTypeName(node->getType());
473 TString functionName = TFunction::unmangleName(node->getName());
474 out << returnType << " " << functionName;
475
476 incrementDepth();
477 // Function definition node contains one or two children nodes
478 // representing function parameters and function body. The latter
479 // is not present in case of empty function bodies.
480 const TIntermSequence& sequence = node->getSequence();
481 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
482 TIntermSequence::const_iterator seqIter = sequence.begin();
483
484 // Traverse function parameters.
485 TIntermAggregate* params = (*seqIter)->getAsAggregate();
486 ASSERT(params != NULL);
487 ASSERT(params->getOp() == EOpParameters);
488 params->traverse(this);
489
490 // Traverse function body.
491 TIntermAggregate* body = ++seqIter != sequence.end() ?
492 (*seqIter)->getAsAggregate() : NULL;
493 visitCodeBlock(body);
494 decrementDepth();
495
496 // Fully processed; no need to visit children.
497 visitChildren = false;
498 break;
499 }
500 case EOpFunctionCall:
501 // Function call.
502 if (visit == PreVisit)
503 {
504 TString functionName = TFunction::unmangleName(node->getName());
505 out << functionName << "(";
506 }
507 else if (visit == InVisit)
508 {
509 out << ", ";
510 }
511 else
512 {
513 out << ")";
514 }
515 break;
516 case EOpParameters: {
517 // Function parameters.
518 ASSERT(visit == PreVisit);
519 out << "(";
520 writeFunctionParameters(node->getSequence());
521 out << ")";
522 visitChildren = false;
523 break;
524 }
525 case EOpDeclaration: {
526 // Variable declaration.
527 if (visit == PreVisit)
528 {
529 const TIntermSequence& sequence = node->getSequence();
530 const TIntermTyped* variable = sequence.front()->getAsTyped();
531 writeVariableType(variable->getType());
532 out << " ";
533 mDeclaringVariables = true;
534 }
535 else if (visit == InVisit)
536 {
537 out << ", ";
538 mDeclaringVariables = true;
539 }
540 else
541 {
542 mDeclaringVariables = false;
543 }
544 break;
545 }
546 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
547 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
548 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
549 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
550 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
551 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
552 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
553 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
554 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
555 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
556 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
557 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
558 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
559 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
560 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
561 case EOpConstructStruct:
562 if (visit == PreVisit)
563 {
564 const TType& type = node->getType();
565 ASSERT(type.getBasicType() == EbtStruct);
566 out << type.getTypeName() << "(";
567 }
568 else if (visit == InVisit)
569 {
570 out << ", ";
571 }
572 else
573 {
574 out << ")";
575 }
576 break;
577
578 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
579 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
580 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
581 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
582 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
583 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
584 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
585
586 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
587 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
588 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
589 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
590 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
591 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
592 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
593 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
594 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
595
596 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
597 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
598 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
599 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
600 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
601 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
602 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
603
604 default: UNREACHABLE(); break;
605 }
606 return visitChildren;
607 }
608
visitLoop(Visit visit,TIntermLoop * node)609 bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
610 {
611 TInfoSinkBase& out = objSink();
612
613 incrementDepth();
614 // Loop header.
615 TLoopType loopType = node->getType();
616 if (loopType == ELoopFor) // for loop
617 {
618 out << "for (";
619 if (node->getInit())
620 node->getInit()->traverse(this);
621 out << "; ";
622
623 if (node->getCondition())
624 node->getCondition()->traverse(this);
625 out << "; ";
626
627 if (node->getExpression())
628 node->getExpression()->traverse(this);
629 out << ")\n";
630 }
631 else if (loopType == ELoopWhile) // while loop
632 {
633 out << "while (";
634 ASSERT(node->getCondition() != NULL);
635 node->getCondition()->traverse(this);
636 out << ")\n";
637 }
638 else // do-while loop
639 {
640 ASSERT(loopType == ELoopDoWhile);
641 out << "do\n";
642 }
643
644 // Loop body.
645 visitCodeBlock(node->getBody());
646
647 // Loop footer.
648 if (loopType == ELoopDoWhile) // do-while loop
649 {
650 out << "while (";
651 ASSERT(node->getCondition() != NULL);
652 node->getCondition()->traverse(this);
653 out << ");\n";
654 }
655 decrementDepth();
656
657 // No need to visit children. They have been already processed in
658 // this function.
659 return false;
660 }
661
visitBranch(Visit visit,TIntermBranch * node)662 bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
663 {
664 switch (node->getFlowOp())
665 {
666 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
667 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
668 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
669 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
670 default: UNREACHABLE(); break;
671 }
672
673 return true;
674 }
675
visitCodeBlock(TIntermNode * node)676 void TOutputGLSL::visitCodeBlock(TIntermNode* node) {
677 TInfoSinkBase &out = objSink();
678 if (node != NULL)
679 {
680 node->traverse(this);
681 // Single statements not part of a sequence need to be terminated
682 // with semi-colon.
683 if (isSingleStatement(node))
684 out << ";\n";
685 }
686 else
687 {
688 out << "{\n}\n"; // Empty code block.
689 }
690 }
691