blob: 552fa5066de2ff258faa3bd4db632cac5a297a55 [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();
zmo@google.comf420c422011-09-12 18:27:59 +0000439 TString preString;
440 bool delayedWrite = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000441 switch (node->getOp())
442 {
443 case EOpSequence: {
444 // Scope the sequences except when at the global scope.
445 if (depth > 0) out << "{\n";
446
447 incrementDepth();
448 const TIntermSequence& sequence = node->getSequence();
449 for (TIntermSequence::const_iterator iter = sequence.begin();
450 iter != sequence.end(); ++iter)
451 {
452 TIntermNode* node = *iter;
453 ASSERT(node != NULL);
454 node->traverse(this);
455
456 if (isSingleStatement(node))
457 out << ";\n";
458 }
459 decrementDepth();
460
461 // Scope the sequences except when at the global scope.
462 if (depth > 0) out << "}\n";
463 visitChildren = false;
464 break;
465 }
466 case EOpPrototype: {
467 // Function declaration.
468 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000469 writeVariableType(node->getType());
470 out << " " << node->getName();
zmo@google.com5601ea02011-06-10 18:23:25 +0000471
472 out << "(";
473 writeFunctionParameters(node->getSequence());
474 out << ")";
475
476 visitChildren = false;
477 break;
478 }
479 case EOpFunction: {
480 // Function definition.
481 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000482 writeVariableType(node->getType());
483 out << " " << TFunction::unmangleName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000484
485 incrementDepth();
486 // Function definition node contains one or two children nodes
487 // representing function parameters and function body. The latter
488 // is not present in case of empty function bodies.
489 const TIntermSequence& sequence = node->getSequence();
490 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
491 TIntermSequence::const_iterator seqIter = sequence.begin();
492
493 // Traverse function parameters.
494 TIntermAggregate* params = (*seqIter)->getAsAggregate();
495 ASSERT(params != NULL);
496 ASSERT(params->getOp() == EOpParameters);
497 params->traverse(this);
498
499 // Traverse function body.
500 TIntermAggregate* body = ++seqIter != sequence.end() ?
501 (*seqIter)->getAsAggregate() : NULL;
502 visitCodeBlock(body);
503 decrementDepth();
504
505 // Fully processed; no need to visit children.
506 visitChildren = false;
507 break;
508 }
509 case EOpFunctionCall:
510 // Function call.
511 if (visit == PreVisit)
512 {
513 TString functionName = TFunction::unmangleName(node->getName());
514 out << functionName << "(";
515 }
516 else if (visit == InVisit)
517 {
518 out << ", ";
519 }
520 else
521 {
522 out << ")";
523 }
524 break;
525 case EOpParameters: {
526 // Function parameters.
527 ASSERT(visit == PreVisit);
528 out << "(";
529 writeFunctionParameters(node->getSequence());
530 out << ")";
531 visitChildren = false;
532 break;
533 }
534 case EOpDeclaration: {
535 // Variable declaration.
536 if (visit == PreVisit)
537 {
538 const TIntermSequence& sequence = node->getSequence();
539 const TIntermTyped* variable = sequence.front()->getAsTyped();
540 writeVariableType(variable->getType());
541 out << " ";
542 mDeclaringVariables = true;
543 }
544 else if (visit == InVisit)
545 {
546 out << ", ";
547 mDeclaringVariables = true;
548 }
549 else
550 {
551 mDeclaringVariables = false;
552 }
553 break;
554 }
555 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
556 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
557 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
558 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
559 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
560 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
561 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
562 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
563 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
564 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
565 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
566 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
567 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
568 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
569 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
570 case EOpConstructStruct:
571 if (visit == PreVisit)
572 {
573 const TType& type = node->getType();
574 ASSERT(type.getBasicType() == EbtStruct);
575 out << type.getTypeName() << "(";
576 }
577 else if (visit == InVisit)
578 {
579 out << ", ";
580 }
581 else
582 {
583 out << ")";
584 }
585 break;
586
zmo@google.comf420c422011-09-12 18:27:59 +0000587 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
588 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
589 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
590 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
591 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
592 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000593 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
594
zmo@google.comf420c422011-09-12 18:27:59 +0000595 case EOpMod: preString = "mod("; delayedWrite = true; break;
596 case EOpPow: preString = "pow("; delayedWrite = true; break;
597 case EOpAtan: preString = "atan("; delayedWrite = true; break;
598 case EOpMin: preString = "min("; delayedWrite = true; break;
599 case EOpMax: preString = "max("; delayedWrite = true; break;
600 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
601 case EOpMix: preString = "mix("; delayedWrite = true; break;
602 case EOpStep: preString = "step("; delayedWrite = true; break;
603 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000604
zmo@google.comf420c422011-09-12 18:27:59 +0000605 case EOpDistance: preString = "distance("; delayedWrite = true; break;
606 case EOpDot: preString = "dot("; delayedWrite = true; break;
607 case EOpCross: preString = "cross("; delayedWrite = true; break;
608 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
609 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
610 case EOpRefract: preString = "refract("; delayedWrite = true; break;
611 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000612
613 default: UNREACHABLE(); break;
614 }
zmo@google.comf420c422011-09-12 18:27:59 +0000615 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
616 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
617 if (delayedWrite)
618 writeTriplet(visit, preString.c_str(), ", ", ")");
zmo@google.com5601ea02011-06-10 18:23:25 +0000619 return visitChildren;
620}
621
622bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
623{
624 TInfoSinkBase& out = objSink();
625
626 incrementDepth();
627 // Loop header.
628 TLoopType loopType = node->getType();
629 if (loopType == ELoopFor) // for loop
630 {
631 if (!node->getUnrollFlag()) {
632 out << "for (";
633 if (node->getInit())
634 node->getInit()->traverse(this);
635 out << "; ";
636
637 if (node->getCondition())
638 node->getCondition()->traverse(this);
639 out << "; ";
640
641 if (node->getExpression())
642 node->getExpression()->traverse(this);
643 out << ")\n";
644 }
645 }
646 else if (loopType == ELoopWhile) // while loop
647 {
648 out << "while (";
649 ASSERT(node->getCondition() != NULL);
650 node->getCondition()->traverse(this);
651 out << ")\n";
652 }
653 else // do-while loop
654 {
655 ASSERT(loopType == ELoopDoWhile);
656 out << "do\n";
657 }
658
659 // Loop body.
660 if (node->getUnrollFlag())
661 {
662 TLoopIndexInfo indexInfo;
663 mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
664 mLoopUnroll.Push(indexInfo);
665 while (mLoopUnroll.SatisfiesLoopCondition())
666 {
667 visitCodeBlock(node->getBody());
668 mLoopUnroll.Step();
669 }
670 mLoopUnroll.Pop();
671 }
672 else
673 {
674 visitCodeBlock(node->getBody());
675 }
676
677 // Loop footer.
678 if (loopType == ELoopDoWhile) // do-while loop
679 {
680 out << "while (";
681 ASSERT(node->getCondition() != NULL);
682 node->getCondition()->traverse(this);
683 out << ");\n";
684 }
685 decrementDepth();
686
687 // No need to visit children. They have been already processed in
688 // this function.
689 return false;
690}
691
692bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
693{
694 switch (node->getFlowOp())
695 {
696 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
697 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
698 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
699 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
700 default: UNREACHABLE(); break;
701 }
702
703 return true;
704}
705
706void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
707 TInfoSinkBase &out = objSink();
708 if (node != NULL)
709 {
710 node->traverse(this);
711 // Single statements not part of a sequence need to be terminated
712 // with semi-colon.
713 if (isSingleStatement(node))
714 out << ";\n";
715 }
716 else
717 {
718 out << "{\n}\n"; // Empty code block.
719 }
720}