blob: a0feb07eb352d0b61e3127096c65a04c185dc3ce [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
2// Copyright (c) 2002-2011 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/OutputGLSLBase.h"
8#include "compiler/debug.h"
9
10namespace
11{
12TString 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
41TString arrayBrackets(const TType& type)
42{
43 ASSERT(type.isArray());
44 TInfoSinkBase out;
45 out << "[" << type.getArraySize() << "]";
46 return TString(out.c_str());
47}
48
49bool 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
69TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
70 : TIntermTraverser(true, true, true),
71 mObjSink(objSink),
72 mDeclaringVariables(false)
73{
74}
75
76void TOutputGLSLBase::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
93void TOutputGLSLBase::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 // Declare the struct if we have not done so already.
101 if ((type.getBasicType() == EbtStruct) &&
102 (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
103 {
104 out << "struct " << type.getTypeName() << "{\n";
105 const TTypeList* structure = type.getStruct();
106 ASSERT(structure != NULL);
107 for (size_t i = 0; i < structure->size(); ++i)
108 {
109 const TType* fieldType = (*structure)[i].type;
110 ASSERT(fieldType != NULL);
111 if (writeVariablePrecision(fieldType->getPrecision()))
112 out << " ";
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 if (writeVariablePrecision(type.getPrecision()))
124 out << " ";
125 out << getTypeName(type);
126 }
127}
128
129void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
130{
131 TInfoSinkBase& out = objSink();
132 for (TIntermSequence::const_iterator iter = args.begin();
133 iter != args.end(); ++iter)
134 {
135 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
136 ASSERT(arg != NULL);
137
138 const TType& type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000139 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000140
141 const TString& name = arg->getSymbol();
142 if (!name.empty())
143 out << " " << name;
144 if (type.isArray())
145 out << arrayBrackets(type);
146
147 // Put a comma if this is not the last argument.
148 if (iter != args.end() - 1)
149 out << ", ";
150 }
151}
152
153const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
154 const ConstantUnion* pConstUnion)
155{
156 TInfoSinkBase& out = objSink();
157
158 if (type.getBasicType() == EbtStruct)
159 {
160 out << type.getTypeName() << "(";
161 const TTypeList* structure = type.getStruct();
162 ASSERT(structure != NULL);
163 for (size_t i = 0; i < structure->size(); ++i)
164 {
165 const TType* fieldType = (*structure)[i].type;
166 ASSERT(fieldType != NULL);
167 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
168 if (i != structure->size() - 1) out << ", ";
169 }
170 out << ")";
171 }
172 else
173 {
174 int size = type.getObjectSize();
175 bool writeType = size > 1;
176 if (writeType) out << getTypeName(type) << "(";
177 for (int i = 0; i < size; ++i, ++pConstUnion)
178 {
179 switch (pConstUnion->getType())
180 {
181 case EbtFloat: out << pConstUnion->getFConst(); break;
182 case EbtInt: out << pConstUnion->getIConst(); break;
183 case EbtBool: out << pConstUnion->getBConst(); break;
184 default: UNREACHABLE();
185 }
186 if (i != size - 1) out << ", ";
187 }
188 if (writeType) out << ")";
189 }
190 return pConstUnion;
191}
192
193void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
194{
195 TInfoSinkBase& out = objSink();
196 if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
197 out << mLoopUnroll.GetLoopIndexValue(node);
198 else
199 out << node->getSymbol();
200
201 if (mDeclaringVariables && node->getType().isArray())
202 out << arrayBrackets(node->getType());
203}
204
205void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
206{
207 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
208}
209
210bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
211{
212 bool visitChildren = true;
213 TInfoSinkBase& out = objSink();
214 switch (node->getOp())
215 {
216 case EOpInitialize:
217 if (visit == InVisit)
218 {
219 out << " = ";
220 // RHS of initialize is not being declared.
221 mDeclaringVariables = false;
222 }
223 break;
224 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
225 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
226 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
227 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
228 // Notice the fall-through.
229 case EOpMulAssign:
230 case EOpVectorTimesMatrixAssign:
231 case EOpVectorTimesScalarAssign:
232 case EOpMatrixTimesScalarAssign:
233 case EOpMatrixTimesMatrixAssign:
234 writeTriplet(visit, "(", " *= ", ")");
235 break;
236
237 case EOpIndexDirect:
238 case EOpIndexIndirect:
239 writeTriplet(visit, NULL, "[", "]");
240 break;
241 case EOpIndexDirectStruct:
242 if (visit == InVisit)
243 {
244 out << ".";
245 // TODO(alokp): ASSERT
246 out << node->getType().getFieldName();
247 visitChildren = false;
248 }
249 break;
250 case EOpVectorSwizzle:
251 if (visit == InVisit)
252 {
253 out << ".";
254 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
255 TIntermSequence& sequence = rightChild->getSequence();
256 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
257 {
258 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
259 ASSERT(element->getBasicType() == EbtInt);
260 ASSERT(element->getNominalSize() == 1);
261 const ConstantUnion& data = element->getUnionArrayPointer()[0];
262 ASSERT(data.getType() == EbtInt);
263 switch (data.getIConst())
264 {
265 case 0: out << "x"; break;
266 case 1: out << "y"; break;
267 case 2: out << "z"; break;
268 case 3: out << "w"; break;
269 default: UNREACHABLE(); break;
270 }
271 }
272 visitChildren = false;
273 }
274 break;
275
276 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
277 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
278 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
279 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
280 case EOpMod: UNIMPLEMENTED(); break;
281 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
282 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
283 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
284 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
285 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
286 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
287
288 // Notice the fall-through.
289 case EOpVectorTimesScalar:
290 case EOpVectorTimesMatrix:
291 case EOpMatrixTimesVector:
292 case EOpMatrixTimesScalar:
293 case EOpMatrixTimesMatrix:
294 writeTriplet(visit, "(", " * ", ")");
295 break;
296
297 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
298 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
299 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
300 default: UNREACHABLE(); break;
301 }
302
303 return visitChildren;
304}
305
306bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
307{
308 switch (node->getOp())
309 {
310 case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
311 case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
312 case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
313
314 case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
315 case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
316 case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
317 case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
318
319 case EOpConvIntToBool:
320 case EOpConvFloatToBool:
321 switch (node->getOperand()->getType().getNominalSize())
322 {
323 case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
324 case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
325 case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
326 case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
327 default: UNREACHABLE();
328 }
329 break;
330 case EOpConvBoolToFloat:
331 case EOpConvIntToFloat:
332 switch (node->getOperand()->getType().getNominalSize())
333 {
334 case 1: writeTriplet(visit, "float(", NULL, ")"); break;
335 case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
336 case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
337 case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
338 default: UNREACHABLE();
339 }
340 break;
341 case EOpConvFloatToInt:
342 case EOpConvBoolToInt:
343 switch (node->getOperand()->getType().getNominalSize())
344 {
345 case 1: writeTriplet(visit, "int(", NULL, ")"); break;
346 case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
347 case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
348 case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
349 default: UNREACHABLE();
350 }
351 break;
352
353 case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
354 case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
355 case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
356 case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
357 case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
358 case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
359 case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
360 case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
361
362 case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
363 case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
364 case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
365 case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
366 case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
367 case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
368
369 case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
370 case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
371 case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
372 case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
373 case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
374
375 case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
376 case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
377
378 case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break;
379 case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break;
380 case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break;
381
382 case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
383 case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
384
385 default: UNREACHABLE(); break;
386 }
387
388 return true;
389}
390
391bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
392{
393 TInfoSinkBase& out = objSink();
394
395 if (node->usesTernaryOperator())
396 {
397 // Notice two brackets at the beginning and end. The outer ones
398 // encapsulate the whole ternary expression. This preserves the
399 // order of precedence when ternary expressions are used in a
400 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
401 out << "((";
402 node->getCondition()->traverse(this);
403 out << ") ? (";
404 node->getTrueBlock()->traverse(this);
405 out << ") : (";
406 node->getFalseBlock()->traverse(this);
407 out << "))";
408 }
409 else
410 {
411 out << "if (";
412 node->getCondition()->traverse(this);
413 out << ")\n";
414
415 incrementDepth();
416 visitCodeBlock(node->getTrueBlock());
417
418 if (node->getFalseBlock())
419 {
420 out << "else\n";
421 visitCodeBlock(node->getFalseBlock());
422 }
423 decrementDepth();
424 }
425 return false;
426}
427
428bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
429{
430 bool visitChildren = true;
431 TInfoSinkBase& out = objSink();
432 switch (node->getOp())
433 {
434 case EOpSequence: {
435 // Scope the sequences except when at the global scope.
436 if (depth > 0) out << "{\n";
437
438 incrementDepth();
439 const TIntermSequence& sequence = node->getSequence();
440 for (TIntermSequence::const_iterator iter = sequence.begin();
441 iter != sequence.end(); ++iter)
442 {
443 TIntermNode* node = *iter;
444 ASSERT(node != NULL);
445 node->traverse(this);
446
447 if (isSingleStatement(node))
448 out << ";\n";
449 }
450 decrementDepth();
451
452 // Scope the sequences except when at the global scope.
453 if (depth > 0) out << "}\n";
454 visitChildren = false;
455 break;
456 }
457 case EOpPrototype: {
458 // Function declaration.
459 ASSERT(visit == PreVisit);
460 TString returnType = getTypeName(node->getType());
461 out << returnType << " " << node->getName();
462
463 out << "(";
464 writeFunctionParameters(node->getSequence());
465 out << ")";
466
467 visitChildren = false;
468 break;
469 }
470 case EOpFunction: {
471 // Function definition.
472 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000473 writeVariableType(node->getType());
474 out << " " << TFunction::unmangleName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000475
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
609bool TOutputGLSLBase::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 if (!node->getUnrollFlag()) {
619 out << "for (";
620 if (node->getInit())
621 node->getInit()->traverse(this);
622 out << "; ";
623
624 if (node->getCondition())
625 node->getCondition()->traverse(this);
626 out << "; ";
627
628 if (node->getExpression())
629 node->getExpression()->traverse(this);
630 out << ")\n";
631 }
632 }
633 else if (loopType == ELoopWhile) // while loop
634 {
635 out << "while (";
636 ASSERT(node->getCondition() != NULL);
637 node->getCondition()->traverse(this);
638 out << ")\n";
639 }
640 else // do-while loop
641 {
642 ASSERT(loopType == ELoopDoWhile);
643 out << "do\n";
644 }
645
646 // Loop body.
647 if (node->getUnrollFlag())
648 {
649 TLoopIndexInfo indexInfo;
650 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
651 mLoopUnroll.Push(indexInfo);
652 while (mLoopUnroll.SatisfiesLoopCondition())
653 {
654 visitCodeBlock(node->getBody());
655 mLoopUnroll.Step();
656 }
657 mLoopUnroll.Pop();
658 }
659 else
660 {
661 visitCodeBlock(node->getBody());
662 }
663
664 // Loop footer.
665 if (loopType == ELoopDoWhile) // do-while loop
666 {
667 out << "while (";
668 ASSERT(node->getCondition() != NULL);
669 node->getCondition()->traverse(this);
670 out << ");\n";
671 }
672 decrementDepth();
673
674 // No need to visit children. They have been already processed in
675 // this function.
676 return false;
677}
678
679bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
680{
681 switch (node->getFlowOp())
682 {
683 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
684 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
685 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
686 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
687 default: UNREACHABLE(); break;
688 }
689
690 return true;
691}
692
693void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
694 TInfoSinkBase &out = objSink();
695 if (node != NULL)
696 {
697 node->traverse(this);
698 // Single statements not part of a sequence need to be terminated
699 // with semi-colon.
700 if (isSingleStatement(node))
701 out << ";\n";
702 }
703 else
704 {
705 out << "{\n}\n"; // Empty code block.
706 }
707}