blob: 36d054ea03b33260e47e4a2c3806407a3ef4252f [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{
zmo@google.com32e97312011-08-24 01:03:11 +0000308 TString preString;
309 TString postString = ")";
310
zmo@google.com5601ea02011-06-10 18:23:25 +0000311 switch (node->getOp())
312 {
zmo@google.com32e97312011-08-24 01:03:11 +0000313 case EOpNegative: preString = "(-"; break;
314 case EOpVectorLogicalNot: preString = "not("; break;
315 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000316
zmo@google.com32e97312011-08-24 01:03:11 +0000317 case EOpPostIncrement: preString = "("; postString = "++)"; break;
318 case EOpPostDecrement: preString = "("; postString = "--)"; break;
319 case EOpPreIncrement: preString = "(++"; break;
320 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000321
322 case EOpConvIntToBool:
323 case EOpConvFloatToBool:
324 switch (node->getOperand()->getType().getNominalSize())
325 {
zmo@google.com32e97312011-08-24 01:03:11 +0000326 case 1: preString = "bool("; break;
327 case 2: preString = "bvec2("; break;
328 case 3: preString = "bvec3("; break;
329 case 4: preString = "bvec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000330 default: UNREACHABLE();
331 }
332 break;
333 case EOpConvBoolToFloat:
334 case EOpConvIntToFloat:
335 switch (node->getOperand()->getType().getNominalSize())
336 {
zmo@google.com32e97312011-08-24 01:03:11 +0000337 case 1: preString = "float("; break;
338 case 2: preString = "vec2("; break;
339 case 3: preString = "vec3("; break;
340 case 4: preString = "vec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000341 default: UNREACHABLE();
342 }
343 break;
344 case EOpConvFloatToInt:
345 case EOpConvBoolToInt:
346 switch (node->getOperand()->getType().getNominalSize())
347 {
zmo@google.com32e97312011-08-24 01:03:11 +0000348 case 1: preString = "int("; break;
349 case 2: preString = "ivec2("; break;
350 case 3: preString = "ivec3("; break;
351 case 4: preString = "ivec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000352 default: UNREACHABLE();
353 }
354 break;
355
zmo@google.com32e97312011-08-24 01:03:11 +0000356 case EOpRadians: preString = "radians("; break;
357 case EOpDegrees: preString = "degrees("; break;
358 case EOpSin: preString = "sin("; break;
359 case EOpCos: preString = "cos("; break;
360 case EOpTan: preString = "tan("; break;
361 case EOpAsin: preString = "asin("; break;
362 case EOpAcos: preString = "acos("; break;
363 case EOpAtan: preString = "atan("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000364
zmo@google.com32e97312011-08-24 01:03:11 +0000365 case EOpExp: preString = "exp("; break;
366 case EOpLog: preString = "log("; break;
367 case EOpExp2: preString = "exp2("; break;
368 case EOpLog2: preString = "log2("; break;
369 case EOpSqrt: preString = "sqrt("; break;
370 case EOpInverseSqrt: preString = "inversesqrt("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000371
zmo@google.com32e97312011-08-24 01:03:11 +0000372 case EOpAbs: preString = "abs("; break;
373 case EOpSign: preString = "sign("; break;
374 case EOpFloor: preString = "floor("; break;
375 case EOpCeil: preString = "ceil("; break;
376 case EOpFract: preString = "fract("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000377
zmo@google.com32e97312011-08-24 01:03:11 +0000378 case EOpLength: preString = "length("; break;
379 case EOpNormalize: preString = "normalize("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000380
zmo@google.com32e97312011-08-24 01:03:11 +0000381 case EOpDFdx: preString = "dFdx("; break;
382 case EOpDFdy: preString = "dFdy("; break;
383 case EOpFwidth: preString = "fwidth("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000384
zmo@google.com32e97312011-08-24 01:03:11 +0000385 case EOpAny: preString = "any("; break;
386 case EOpAll: preString = "all("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000387
388 default: UNREACHABLE(); break;
389 }
390
zmo@google.com32e97312011-08-24 01:03:11 +0000391 if (visit == PreVisit && node->getUseEmulatedFunction())
392 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
393 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
394
zmo@google.com5601ea02011-06-10 18:23:25 +0000395 return true;
396}
397
398bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
399{
400 TInfoSinkBase& out = objSink();
401
402 if (node->usesTernaryOperator())
403 {
404 // Notice two brackets at the beginning and end. The outer ones
405 // encapsulate the whole ternary expression. This preserves the
406 // order of precedence when ternary expressions are used in a
407 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
408 out << "((";
409 node->getCondition()->traverse(this);
410 out << ") ? (";
411 node->getTrueBlock()->traverse(this);
412 out << ") : (";
413 node->getFalseBlock()->traverse(this);
414 out << "))";
415 }
416 else
417 {
418 out << "if (";
419 node->getCondition()->traverse(this);
420 out << ")\n";
421
422 incrementDepth();
423 visitCodeBlock(node->getTrueBlock());
424
425 if (node->getFalseBlock())
426 {
427 out << "else\n";
428 visitCodeBlock(node->getFalseBlock());
429 }
430 decrementDepth();
431 }
432 return false;
433}
434
435bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
436{
437 bool visitChildren = true;
438 TInfoSinkBase& out = objSink();
439 switch (node->getOp())
440 {
441 case EOpSequence: {
442 // Scope the sequences except when at the global scope.
443 if (depth > 0) out << "{\n";
444
445 incrementDepth();
446 const TIntermSequence& sequence = node->getSequence();
447 for (TIntermSequence::const_iterator iter = sequence.begin();
448 iter != sequence.end(); ++iter)
449 {
450 TIntermNode* node = *iter;
451 ASSERT(node != NULL);
452 node->traverse(this);
453
454 if (isSingleStatement(node))
455 out << ";\n";
456 }
457 decrementDepth();
458
459 // Scope the sequences except when at the global scope.
460 if (depth > 0) out << "}\n";
461 visitChildren = false;
462 break;
463 }
464 case EOpPrototype: {
465 // Function declaration.
466 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000467 writeVariableType(node->getType());
468 out << " " << node->getName();
zmo@google.com5601ea02011-06-10 18:23:25 +0000469
470 out << "(";
471 writeFunctionParameters(node->getSequence());
472 out << ")";
473
474 visitChildren = false;
475 break;
476 }
477 case EOpFunction: {
478 // Function definition.
479 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000480 writeVariableType(node->getType());
481 out << " " << TFunction::unmangleName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000482
483 incrementDepth();
484 // Function definition node contains one or two children nodes
485 // representing function parameters and function body. The latter
486 // is not present in case of empty function bodies.
487 const TIntermSequence& sequence = node->getSequence();
488 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
489 TIntermSequence::const_iterator seqIter = sequence.begin();
490
491 // Traverse function parameters.
492 TIntermAggregate* params = (*seqIter)->getAsAggregate();
493 ASSERT(params != NULL);
494 ASSERT(params->getOp() == EOpParameters);
495 params->traverse(this);
496
497 // Traverse function body.
498 TIntermAggregate* body = ++seqIter != sequence.end() ?
499 (*seqIter)->getAsAggregate() : NULL;
500 visitCodeBlock(body);
501 decrementDepth();
502
503 // Fully processed; no need to visit children.
504 visitChildren = false;
505 break;
506 }
507 case EOpFunctionCall:
508 // Function call.
509 if (visit == PreVisit)
510 {
511 TString functionName = TFunction::unmangleName(node->getName());
512 out << functionName << "(";
513 }
514 else if (visit == InVisit)
515 {
516 out << ", ";
517 }
518 else
519 {
520 out << ")";
521 }
522 break;
523 case EOpParameters: {
524 // Function parameters.
525 ASSERT(visit == PreVisit);
526 out << "(";
527 writeFunctionParameters(node->getSequence());
528 out << ")";
529 visitChildren = false;
530 break;
531 }
532 case EOpDeclaration: {
533 // Variable declaration.
534 if (visit == PreVisit)
535 {
536 const TIntermSequence& sequence = node->getSequence();
537 const TIntermTyped* variable = sequence.front()->getAsTyped();
538 writeVariableType(variable->getType());
539 out << " ";
540 mDeclaringVariables = true;
541 }
542 else if (visit == InVisit)
543 {
544 out << ", ";
545 mDeclaringVariables = true;
546 }
547 else
548 {
549 mDeclaringVariables = false;
550 }
551 break;
552 }
553 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
554 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
555 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
556 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
557 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
558 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
559 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
560 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
561 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
562 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
563 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
564 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
565 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
566 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
567 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
568 case EOpConstructStruct:
569 if (visit == PreVisit)
570 {
571 const TType& type = node->getType();
572 ASSERT(type.getBasicType() == EbtStruct);
573 out << type.getTypeName() << "(";
574 }
575 else if (visit == InVisit)
576 {
577 out << ", ";
578 }
579 else
580 {
581 out << ")";
582 }
583 break;
584
585 case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
586 case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
587 case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
588 case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
589 case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
590 case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
591 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
592
593 case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
594 case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
595 case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
596 case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
597 case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
598 case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
599 case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
600 case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
601 case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
602
603 case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
604 case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
605 case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
606 case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
607 case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
608 case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
609 case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
610
611 default: UNREACHABLE(); break;
612 }
613 return visitChildren;
614}
615
616bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
617{
618 TInfoSinkBase& out = objSink();
619
620 incrementDepth();
621 // Loop header.
622 TLoopType loopType = node->getType();
623 if (loopType == ELoopFor) // for loop
624 {
625 if (!node->getUnrollFlag()) {
626 out << "for (";
627 if (node->getInit())
628 node->getInit()->traverse(this);
629 out << "; ";
630
631 if (node->getCondition())
632 node->getCondition()->traverse(this);
633 out << "; ";
634
635 if (node->getExpression())
636 node->getExpression()->traverse(this);
637 out << ")\n";
638 }
639 }
640 else if (loopType == ELoopWhile) // while loop
641 {
642 out << "while (";
643 ASSERT(node->getCondition() != NULL);
644 node->getCondition()->traverse(this);
645 out << ")\n";
646 }
647 else // do-while loop
648 {
649 ASSERT(loopType == ELoopDoWhile);
650 out << "do\n";
651 }
652
653 // Loop body.
654 if (node->getUnrollFlag())
655 {
656 TLoopIndexInfo indexInfo;
657 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
658 mLoopUnroll.Push(indexInfo);
659 while (mLoopUnroll.SatisfiesLoopCondition())
660 {
661 visitCodeBlock(node->getBody());
662 mLoopUnroll.Step();
663 }
664 mLoopUnroll.Pop();
665 }
666 else
667 {
668 visitCodeBlock(node->getBody());
669 }
670
671 // Loop footer.
672 if (loopType == ELoopDoWhile) // do-while loop
673 {
674 out << "while (";
675 ASSERT(node->getCondition() != NULL);
676 node->getCondition()->traverse(this);
677 out << ");\n";
678 }
679 decrementDepth();
680
681 // No need to visit children. They have been already processed in
682 // this function.
683 return false;
684}
685
686bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
687{
688 switch (node->getFlowOp())
689 {
690 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
691 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
692 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
693 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
694 default: UNREACHABLE(); break;
695 }
696
697 return true;
698}
699
700void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
701 TInfoSinkBase &out = objSink();
702 if (node != NULL)
703 {
704 node->traverse(this);
705 // Single statements not part of a sequence need to be terminated
706 // with semi-colon.
707 if (isSingleStatement(node))
708 out << ";\n";
709 }
710 else
711 {
712 out << "{\n}\n"; // Empty code block.
713 }
714}