1//
2// Copyright (c) 2002-2014 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/translator/OutputGLSLBase.h"
8
9#include "common/debug.h"
10
11#include <cfloat>
12
13namespace
14{
15TString arrayBrackets(const TType &type)
16{
17 ASSERT(type.isArray());
18 TInfoSinkBase out;
19 out << "[" << type.getArraySize() << "]";
20 return TString(out.c_str());
21}
22
23bool isSingleStatement(TIntermNode *node)
24{
25 if (const TIntermAggregate *aggregate = node->getAsAggregate())
26 {
27 return (aggregate->getOp() != EOpFunction) &&
28 (aggregate->getOp() != EOpSequence);
29 }
30 else if (const TIntermSelection *selection = node->getAsSelectionNode())
31 {
32 // Ternary operators are usually part of an assignment operator.
33 // This handles those rare cases in which they are all by themselves.
34 return selection->usesTernaryOperator();
35 }
36 else if (node->getAsLoopNode())
37 {
38 return false;
39 }
40 else if (node->getAsSwitchNode())
41 {
42 return false;
43 }
44 else if (node->getAsCaseNode())
45 {
46 return false;
47 }
48 return true;
49}
50
51} // namespace
52
53TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
54 ShArrayIndexClampingStrategy clampingStrategy,
55 ShHashFunction64 hashFunction,
56 NameMap &nameMap,
57 TSymbolTable &symbolTable,
58 int shaderVersion,
59 ShShaderOutput output)
60 : TIntermTraverser(true, true, true),
61 mObjSink(objSink),
62 mDeclaringVariables(false),
63 mClampingStrategy(clampingStrategy),
64 mHashFunction(hashFunction),
65 mNameMap(nameMap),
66 mSymbolTable(symbolTable),
67 mShaderVersion(shaderVersion),
68 mOutput(output)
69{
70}
71
72void TOutputGLSLBase::writeTriplet(
73 Visit visit, const char *preStr, const char *inStr, const char *postStr)
74{
75 TInfoSinkBase &out = objSink();
76 if (visit == PreVisit && preStr)
77 out << preStr;
78 else if (visit == InVisit && inStr)
79 out << inStr;
80 else if (visit == PostVisit && postStr)
81 out << postStr;
82}
83
84void TOutputGLSLBase::writeBuiltInFunctionTriplet(
85 Visit visit, const char *preStr, bool useEmulatedFunction)
86{
87 TString preString = useEmulatedFunction ?
88 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
89 writeTriplet(visit, preString.c_str(), ", ", ")");
90}
91
92void TOutputGLSLBase::writeVariableType(const TType &type)
93{
94 TInfoSinkBase &out = objSink();
95 TQualifier qualifier = type.getQualifier();
96 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
97 {
98 if (IsGLSL130OrNewer(mOutput))
99 {
100 switch (qualifier)
101 {
102 case EvqAttribute:
103 out << "in" << " ";
104 break;
105 case EvqVaryingIn:
106 out << "in" << " ";
107 break;
108 case EvqVaryingOut:
109 out << "out" << " ";
110 break;
111 case EvqInvariantVaryingIn:
112 out << "invariant in" << " ";
113 break;
114 case EvqInvariantVaryingOut:
115 out << "invariant out" << " ";
116 break;
117 default:
118 out << type.getQualifierString() << " ";
119 break;
120 }
121 }
122 else
123 {
124 out << type.getQualifierString() << " ";
125 }
126 }
127 // Declare the struct if we have not done so already.
128 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
129 {
130 TStructure *structure = type.getStruct();
131
132 declareStruct(structure);
133
134 if (!structure->name().empty())
135 {
136 mDeclaredStructs.insert(structure->uniqueId());
137 }
138 }
139 else
140 {
141 if (writeVariablePrecision(type.getPrecision()))
142 out << " ";
143 out << getTypeName(type);
144 }
145}
146
147void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
148{
149 TInfoSinkBase &out = objSink();
150 for (TIntermSequence::const_iterator iter = args.begin();
151 iter != args.end(); ++iter)
152 {
153 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
154 ASSERT(arg != NULL);
155
156 const TType &type = arg->getType();
157 writeVariableType(type);
158
159 const TString &name = arg->getSymbol();
160 if (!name.empty())
161 out << " " << hashName(name);
162 if (type.isArray())
163 out << arrayBrackets(type);
164
165 // Put a comma if this is not the last argument.
166 if (iter != args.end() - 1)
167 out << ", ";
168 }
169}
170
171const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
172 const TType &type, const TConstantUnion *pConstUnion)
173{
174 TInfoSinkBase &out = objSink();
175
176 if (type.getBasicType() == EbtStruct)
177 {
178 const TStructure *structure = type.getStruct();
179 out << hashName(structure->name()) << "(";
180
181 const TFieldList &fields = structure->fields();
182 for (size_t i = 0; i < fields.size(); ++i)
183 {
184 const TType *fieldType = fields[i]->type();
185 ASSERT(fieldType != NULL);
186 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
187 if (i != fields.size() - 1)
188 out << ", ";
189 }
190 out << ")";
191 }
192 else
193 {
194 size_t size = type.getObjectSize();
195 bool writeType = size > 1;
196 if (writeType)
197 out << getTypeName(type) << "(";
198 for (size_t i = 0; i < size; ++i, ++pConstUnion)
199 {
200 switch (pConstUnion->getType())
201 {
202 case EbtFloat:
203 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
204 break;
205 case EbtInt:
206 out << pConstUnion->getIConst();
207 break;
208 case EbtUInt:
209 out << pConstUnion->getUConst() << "u";
210 break;
211 case EbtBool:
212 out << pConstUnion->getBConst();
213 break;
214 default: UNREACHABLE();
215 }
216 if (i != size - 1)
217 out << ", ";
218 }
219 if (writeType)
220 out << ")";
221 }
222 return pConstUnion;
223}
224
225void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
226{
227 TInfoSinkBase &out = objSink();
228 if (visit == PreVisit)
229 {
230 if (type.isArray())
231 {
232 out << constructorBaseType;
233 out << arrayBrackets(type);
234 out << "(";
235 }
236 else
237 {
238 out << constructorBaseType << "(";
239 }
240 }
241 else
242 {
243 writeTriplet(visit, nullptr, ", ", ")");
244 }
245}
246
247void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
248{
249 TInfoSinkBase &out = objSink();
250 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
251 out << mLoopUnrollStack.getLoopIndexValue(node);
252 else
253 out << hashVariableName(node->getSymbol());
254
255 if (mDeclaringVariables && node->getType().isArray())
256 out << arrayBrackets(node->getType());
257}
258
259void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
260{
261 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
262}
263
264bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
265{
266 bool visitChildren = true;
267 TInfoSinkBase &out = objSink();
268 switch (node->getOp())
269 {
270 case EOpInitialize:
271 if (visit == InVisit)
272 {
273 out << " = ";
274 // RHS of initialize is not being declared.
275 mDeclaringVariables = false;
276 }
277 break;
278 case EOpAssign:
279 writeTriplet(visit, "(", " = ", ")");
280 break;
281 case EOpAddAssign:
282 writeTriplet(visit, "(", " += ", ")");
283 break;
284 case EOpSubAssign:
285 writeTriplet(visit, "(", " -= ", ")");
286 break;
287 case EOpDivAssign:
288 writeTriplet(visit, "(", " /= ", ")");
289 break;
290 case EOpIModAssign:
291 writeTriplet(visit, "(", " %= ", ")");
292 break;
293 // Notice the fall-through.
294 case EOpMulAssign:
295 case EOpVectorTimesMatrixAssign:
296 case EOpVectorTimesScalarAssign:
297 case EOpMatrixTimesScalarAssign:
298 case EOpMatrixTimesMatrixAssign:
299 writeTriplet(visit, "(", " *= ", ")");
300 break;
301 case EOpBitShiftLeftAssign:
302 writeTriplet(visit, "(", " <<= ", ")");
303 break;
304 case EOpBitShiftRightAssign:
305 writeTriplet(visit, "(", " >>= ", ")");
306 break;
307 case EOpBitwiseAndAssign:
308 writeTriplet(visit, "(", " &= ", ")");
309 break;
310 case EOpBitwiseXorAssign:
311 writeTriplet(visit, "(", " ^= ", ")");
312 break;
313 case EOpBitwiseOrAssign:
314 writeTriplet(visit, "(", " |= ", ")");
315 break;
316
317 case EOpIndexDirect:
318 writeTriplet(visit, NULL, "[", "]");
319 break;
320 case EOpIndexIndirect:
321 if (node->getAddIndexClamp())
322 {
323 if (visit == InVisit)
324 {
325 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
326 out << "[int(clamp(float(";
327 else
328 out << "[webgl_int_clamp(";
329 }
330 else if (visit == PostVisit)
331 {
332 int maxSize;
333 TIntermTyped *left = node->getLeft();
334 TType leftType = left->getType();
335
336 if (left->isArray())
337 {
338 // The shader will fail validation if the array length is not > 0.
339 maxSize = leftType.getArraySize() - 1;
340 }
341 else
342 {
343 maxSize = leftType.getNominalSize() - 1;
344 }
345
346 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
347 out << "), 0.0, float(" << maxSize << ")))]";
348 else
349 out << ", 0, " << maxSize << ")]";
350 }
351 }
352 else
353 {
354 writeTriplet(visit, NULL, "[", "]");
355 }
356 break;
357 case EOpIndexDirectStruct:
358 if (visit == InVisit)
359 {
360 // Here we are writing out "foo.bar", where "foo" is struct
361 // and "bar" is field. In AST, it is represented as a binary
362 // node, where left child represents "foo" and right child "bar".
363 // The node itself represents ".". The struct field "bar" is
364 // actually stored as an index into TStructure::fields.
365 out << ".";
366 const TStructure *structure = node->getLeft()->getType().getStruct();
367 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
368 const TField *field = structure->fields()[index->getIConst(0)];
369
370 TString fieldName = field->name();
371 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
372 fieldName = hashName(fieldName);
373
374 out << fieldName;
375 visitChildren = false;
376 }
377 break;
378 case EOpVectorSwizzle:
379 if (visit == InVisit)
380 {
381 out << ".";
382 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
383 TIntermSequence *sequence = rightChild->getSequence();
384 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
385 {
386 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
387 ASSERT(element->getBasicType() == EbtInt);
388 ASSERT(element->getNominalSize() == 1);
389 const TConstantUnion& data = element->getUnionArrayPointer()[0];
390 ASSERT(data.getType() == EbtInt);
391 switch (data.getIConst())
392 {
393 case 0:
394 out << "x";
395 break;
396 case 1:
397 out << "y";
398 break;
399 case 2:
400 out << "z";
401 break;
402 case 3:
403 out << "w";
404 break;
405 default:
406 UNREACHABLE();
407 }
408 }
409 visitChildren = false;
410 }
411 break;
412
413 case EOpAdd:
414 writeTriplet(visit, "(", " + ", ")");
415 break;
416 case EOpSub:
417 writeTriplet(visit, "(", " - ", ")");
418 break;
419 case EOpMul:
420 writeTriplet(visit, "(", " * ", ")");
421 break;
422 case EOpDiv:
423 writeTriplet(visit, "(", " / ", ")");
424 break;
425 case EOpIMod:
426 writeTriplet(visit, "(", " % ", ")");
427 break;
428 case EOpBitShiftLeft:
429 writeTriplet(visit, "(", " << ", ")");
430 break;
431 case EOpBitShiftRight:
432 writeTriplet(visit, "(", " >> ", ")");
433 break;
434 case EOpBitwiseAnd:
435 writeTriplet(visit, "(", " & ", ")");
436 break;
437 case EOpBitwiseXor:
438 writeTriplet(visit, "(", " ^ ", ")");
439 break;
440 case EOpBitwiseOr:
441 writeTriplet(visit, "(", " | ", ")");
442 break;
443
444 case EOpEqual:
445 writeTriplet(visit, "(", " == ", ")");
446 break;
447 case EOpNotEqual:
448 writeTriplet(visit, "(", " != ", ")");
449 break;
450 case EOpLessThan:
451 writeTriplet(visit, "(", " < ", ")");
452 break;
453 case EOpGreaterThan:
454 writeTriplet(visit, "(", " > ", ")");
455 break;
456 case EOpLessThanEqual:
457 writeTriplet(visit, "(", " <= ", ")");
458 break;
459 case EOpGreaterThanEqual:
460 writeTriplet(visit, "(", " >= ", ")");
461 break;
462
463 // Notice the fall-through.
464 case EOpVectorTimesScalar:
465 case EOpVectorTimesMatrix:
466 case EOpMatrixTimesVector:
467 case EOpMatrixTimesScalar:
468 case EOpMatrixTimesMatrix:
469 writeTriplet(visit, "(", " * ", ")");
470 break;
471
472 case EOpLogicalOr:
473 writeTriplet(visit, "(", " || ", ")");
474 break;
475 case EOpLogicalXor:
476 writeTriplet(visit, "(", " ^^ ", ")");
477 break;
478 case EOpLogicalAnd:
479 writeTriplet(visit, "(", " && ", ")");
480 break;
481 default:
482 UNREACHABLE();
483 }
484
485 return visitChildren;
486}
487
488bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
489{
490 TString preString;
491 TString postString = ")";
492
493 switch (node->getOp())
494 {
495 case EOpNegative: preString = "(-"; break;
496 case EOpPositive: preString = "(+"; break;
497 case EOpVectorLogicalNot: preString = "not("; break;
498 case EOpLogicalNot: preString = "(!"; break;
499 case EOpBitwiseNot: preString = "(~"; break;
500
501 case EOpPostIncrement: preString = "("; postString = "++)"; break;
502 case EOpPostDecrement: preString = "("; postString = "--)"; break;
503 case EOpPreIncrement: preString = "(++"; break;
504 case EOpPreDecrement: preString = "(--"; break;
505
506 case EOpRadians:
507 preString = "radians(";
508 break;
509 case EOpDegrees:
510 preString = "degrees(";
511 break;
512 case EOpSin:
513 preString = "sin(";
514 break;
515 case EOpCos:
516 preString = "cos(";
517 break;
518 case EOpTan:
519 preString = "tan(";
520 break;
521 case EOpAsin:
522 preString = "asin(";
523 break;
524 case EOpAcos:
525 preString = "acos(";
526 break;
527 case EOpAtan:
528 preString = "atan(";
529 break;
530
531 case EOpSinh:
532 preString = "sinh(";
533 break;
534 case EOpCosh:
535 preString = "cosh(";
536 break;
537 case EOpTanh:
538 preString = "tanh(";
539 break;
540 case EOpAsinh:
541 preString = "asinh(";
542 break;
543 case EOpAcosh:
544 preString = "acosh(";
545 break;
546 case EOpAtanh:
547 preString = "atanh(";
548 break;
549
550 case EOpExp:
551 preString = "exp(";
552 break;
553 case EOpLog:
554 preString = "log(";
555 break;
556 case EOpExp2:
557 preString = "exp2(";
558 break;
559 case EOpLog2:
560 preString = "log2(";
561 break;
562 case EOpSqrt:
563 preString = "sqrt(";
564 break;
565 case EOpInverseSqrt:
566 preString = "inversesqrt(";
567 break;
568
569 case EOpAbs:
570 preString = "abs(";
571 break;
572 case EOpSign:
573 preString = "sign(";
574 break;
575 case EOpFloor:
576 preString = "floor(";
577 break;
578 case EOpTrunc:
579 preString = "trunc(";
580 break;
581 case EOpRound:
582 preString = "round(";
583 break;
584 case EOpRoundEven:
585 preString = "roundEven(";
586 break;
587 case EOpCeil:
588 preString = "ceil(";
589 break;
590 case EOpFract:
591 preString = "fract(";
592 break;
593 case EOpIsNan:
594 preString = "isnan(";
595 break;
596 case EOpIsInf:
597 preString = "isinf(";
598 break;
599
600 case EOpFloatBitsToInt:
601 preString = "floatBitsToInt(";
602 break;
603 case EOpFloatBitsToUint:
604 preString = "floatBitsToUint(";
605 break;
606 case EOpIntBitsToFloat:
607 preString = "intBitsToFloat(";
608 break;
609 case EOpUintBitsToFloat:
610 preString = "uintBitsToFloat(";
611 break;
612
613 case EOpPackSnorm2x16:
614 preString = "packSnorm2x16(";
615 break;
616 case EOpPackUnorm2x16:
617 preString = "packUnorm2x16(";
618 break;
619 case EOpPackHalf2x16:
620 preString = "packHalf2x16(";
621 break;
622 case EOpUnpackSnorm2x16:
623 preString = "unpackSnorm2x16(";
624 break;
625 case EOpUnpackUnorm2x16:
626 preString = "unpackUnorm2x16(";
627 break;
628 case EOpUnpackHalf2x16:
629 preString = "unpackHalf2x16(";
630 break;
631
632 case EOpLength:
633 preString = "length(";
634 break;
635 case EOpNormalize:
636 preString = "normalize(";
637 break;
638
639 case EOpDFdx:
640 preString = "dFdx(";
641 break;
642 case EOpDFdy:
643 preString = "dFdy(";
644 break;
645 case EOpFwidth:
646 preString = "fwidth(";
647 break;
648
649 case EOpTranspose:
650 preString = "transpose(";
651 break;
652 case EOpDeterminant:
653 preString = "determinant(";
654 break;
655 case EOpInverse:
656 preString = "inverse(";
657 break;
658
659 case EOpAny:
660 preString = "any(";
661 break;
662 case EOpAll:
663 preString = "all(";
664 break;
665
666 default:
667 UNREACHABLE();
668 }
669
670 if (visit == PreVisit && node->getUseEmulatedFunction())
671 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
672 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
673
674 return true;
675}
676
677bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
678{
679 TInfoSinkBase &out = objSink();
680
681 if (node->usesTernaryOperator())
682 {
683 // Notice two brackets at the beginning and end. The outer ones
684 // encapsulate the whole ternary expression. This preserves the
685 // order of precedence when ternary expressions are used in a
686 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
687 out << "((";
688 node->getCondition()->traverse(this);
689 out << ") ? (";
690 node->getTrueBlock()->traverse(this);
691 out << ") : (";
692 node->getFalseBlock()->traverse(this);
693 out << "))";
694 }
695 else
696 {
697 out << "if (";
698 node->getCondition()->traverse(this);
699 out << ")\n";
700
701 incrementDepth(node);
702 visitCodeBlock(node->getTrueBlock());
703
704 if (node->getFalseBlock())
705 {
706 out << "else\n";
707 visitCodeBlock(node->getFalseBlock());
708 }
709 decrementDepth();
710 }
711 return false;
712}
713
714bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
715{
716 if (node->getStatementList())
717 {
718 writeTriplet(visit, "switch (", ") ", nullptr);
719 // The curly braces get written when visiting the statementList aggregate
720 }
721 else
722 {
723 // No statementList, so it won't output curly braces
724 writeTriplet(visit, "switch (", ") {", "}\n");
725 }
726 return true;
727}
728
729bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
730{
731 if (node->hasCondition())
732 {
733 writeTriplet(visit, "case (", nullptr, "):\n");
734 return true;
735 }
736 else
737 {
738 TInfoSinkBase &out = objSink();
739 out << "default:\n";
740 return false;
741 }
742}
743
744bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
745{
746 bool visitChildren = true;
747 TInfoSinkBase &out = objSink();
748 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
749 switch (node->getOp())
750 {
751 case EOpSequence:
752 // Scope the sequences except when at the global scope.
753 if (mDepth > 0)
754 {
755 out << "{\n";
756 }
757
758 incrementDepth(node);
759 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
760 iter != node->getSequence()->end(); ++iter)
761 {
762 TIntermNode *curNode = *iter;
763 ASSERT(curNode != NULL);
764 curNode->traverse(this);
765
766 if (isSingleStatement(curNode))
767 out << ";\n";
768 }
769 decrementDepth();
770
771 // Scope the sequences except when at the global scope.
772 if (mDepth > 0)
773 {
774 out << "}\n";
775 }
776 visitChildren = false;
777 break;
778 case EOpPrototype:
779 // Function declaration.
780 ASSERT(visit == PreVisit);
781 {
782 const TType &type = node->getType();
783 writeVariableType(type);
784 if (type.isArray())
785 out << arrayBrackets(type);
786 }
787
788 out << " " << hashFunctionName(node->getName());
789
790 out << "(";
791 writeFunctionParameters(*(node->getSequence()));
792 out << ")";
793
794 visitChildren = false;
795 break;
796 case EOpFunction: {
797 // Function definition.
798 ASSERT(visit == PreVisit);
799 {
800 const TType &type = node->getType();
801 writeVariableType(type);
802 if (type.isArray())
803 out << arrayBrackets(type);
804 }
805
806 out << " " << hashFunctionName(node->getName());
807
808 incrementDepth(node);
809 // Function definition node contains one or two children nodes
810 // representing function parameters and function body. The latter
811 // is not present in case of empty function bodies.
812 const TIntermSequence &sequence = *(node->getSequence());
813 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
814 TIntermSequence::const_iterator seqIter = sequence.begin();
815
816 // Traverse function parameters.
817 TIntermAggregate *params = (*seqIter)->getAsAggregate();
818 ASSERT(params != NULL);
819 ASSERT(params->getOp() == EOpParameters);
820 params->traverse(this);
821
822 // Traverse function body.
823 TIntermAggregate *body = ++seqIter != sequence.end() ?
824 (*seqIter)->getAsAggregate() : NULL;
825 visitCodeBlock(body);
826 decrementDepth();
827
828 // Fully processed; no need to visit children.
829 visitChildren = false;
830 break;
831 }
832 case EOpFunctionCall:
833 // Function call.
834 if (visit == PreVisit)
835 out << hashFunctionName(node->getName()) << "(";
836 else if (visit == InVisit)
837 out << ", ";
838 else
839 out << ")";
840 break;
841 case EOpInternalFunctionCall:
842 // Function call to an internal helper function.
843 if (visit == PreVisit)
844 out << node->getName() << "(";
845 else if (visit == InVisit)
846 out << ", ";
847 else
848 out << ")";
849 break;
850 case EOpParameters:
851 // Function parameters.
852 ASSERT(visit == PreVisit);
853 out << "(";
854 writeFunctionParameters(*(node->getSequence()));
855 out << ")";
856 visitChildren = false;
857 break;
858 case EOpDeclaration:
859 // Variable declaration.
860 if (visit == PreVisit)
861 {
862 const TIntermSequence &sequence = *(node->getSequence());
863 const TIntermTyped *variable = sequence.front()->getAsTyped();
864 writeVariableType(variable->getType());
865 out << " ";
866 mDeclaringVariables = true;
867 }
868 else if (visit == InVisit)
869 {
870 out << ", ";
871 mDeclaringVariables = true;
872 }
873 else
874 {
875 mDeclaringVariables = false;
876 }
877 break;
878 case EOpInvariantDeclaration:
879 // Invariant declaration.
880 ASSERT(visit == PreVisit);
881 {
882 const TIntermSequence *sequence = node->getSequence();
883 ASSERT(sequence && sequence->size() == 1);
884 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
885 ASSERT(symbol);
886 out << "invariant " << hashVariableName(symbol->getSymbol());
887 }
888 visitChildren = false;
889 break;
890 case EOpConstructFloat:
891 writeConstructorTriplet(visit, node->getType(), "float");
892 break;
893 case EOpConstructVec2:
894 writeConstructorTriplet(visit, node->getType(), "vec2");
895 break;
896 case EOpConstructVec3:
897 writeConstructorTriplet(visit, node->getType(), "vec3");
898 break;
899 case EOpConstructVec4:
900 writeConstructorTriplet(visit, node->getType(), "vec4");
901 break;
902 case EOpConstructBool:
903 writeConstructorTriplet(visit, node->getType(), "bool");
904 break;
905 case EOpConstructBVec2:
906 writeConstructorTriplet(visit, node->getType(), "bvec2");
907 break;
908 case EOpConstructBVec3:
909 writeConstructorTriplet(visit, node->getType(), "bvec3");
910 break;
911 case EOpConstructBVec4:
912 writeConstructorTriplet(visit, node->getType(), "bvec4");
913 break;
914 case EOpConstructInt:
915 writeConstructorTriplet(visit, node->getType(), "int");
916 break;
917 case EOpConstructIVec2:
918 writeConstructorTriplet(visit, node->getType(), "ivec2");
919 break;
920 case EOpConstructIVec3:
921 writeConstructorTriplet(visit, node->getType(), "ivec3");
922 break;
923 case EOpConstructIVec4:
924 writeConstructorTriplet(visit, node->getType(), "ivec4");
925 break;
926 case EOpConstructMat2:
927 writeConstructorTriplet(visit, node->getType(), "mat2");
928 break;
929 case EOpConstructMat3:
930 writeConstructorTriplet(visit, node->getType(), "mat3");
931 break;
932 case EOpConstructMat4:
933 writeConstructorTriplet(visit, node->getType(), "mat4");
934 break;
935 case EOpConstructStruct:
936 {
937 const TType &type = node->getType();
938 ASSERT(type.getBasicType() == EbtStruct);
939 TString constructorName = hashName(type.getStruct()->name());
940 writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
941 break;
942 }
943
944 case EOpOuterProduct:
945 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
946 break;
947
948 case EOpLessThan:
949 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
950 break;
951 case EOpGreaterThan:
952 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
953 break;
954 case EOpLessThanEqual:
955 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
956 break;
957 case EOpGreaterThanEqual:
958 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
959 break;
960 case EOpVectorEqual:
961 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
962 break;
963 case EOpVectorNotEqual:
964 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
965 break;
966 case EOpComma:
967 writeTriplet(visit, "(", ", ", ")");
968 break;
969
970 case EOpMod:
971 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
972 break;
973 case EOpModf:
974 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
975 break;
976 case EOpPow:
977 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
978 break;
979 case EOpAtan:
980 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
981 break;
982 case EOpMin:
983 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
984 break;
985 case EOpMax:
986 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
987 break;
988 case EOpClamp:
989 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
990 break;
991 case EOpMix:
992 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
993 break;
994 case EOpStep:
995 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
996 break;
997 case EOpSmoothStep:
998 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
999 break;
1000 case EOpDistance:
1001 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1002 break;
1003 case EOpDot:
1004 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1005 break;
1006 case EOpCross:
1007 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1008 break;
1009 case EOpFaceForward:
1010 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1011 break;
1012 case EOpReflect:
1013 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1014 break;
1015 case EOpRefract:
1016 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1017 break;
1018 case EOpMul:
1019 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1020 break;
1021
1022 default:
1023 UNREACHABLE();
1024 }
1025 return visitChildren;
1026}
1027
1028bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
1029{
1030 TInfoSinkBase &out = objSink();
1031
1032 incrementDepth(node);
1033 // Loop header.
1034 TLoopType loopType = node->getType();
1035 if (loopType == ELoopFor) // for loop
1036 {
1037 if (!node->getUnrollFlag())
1038 {
1039 out << "for (";
1040 if (node->getInit())
1041 node->getInit()->traverse(this);
1042 out << "; ";
1043
1044 if (node->getCondition())
1045 node->getCondition()->traverse(this);
1046 out << "; ";
1047
1048 if (node->getExpression())
1049 node->getExpression()->traverse(this);
1050 out << ")\n";
1051 }
1052 else
1053 {
1054 // Need to put a one-iteration loop here to handle break.
1055 TIntermSequence *declSeq =
1056 node->getInit()->getAsAggregate()->getSequence();
1057 TIntermSymbol *indexSymbol =
1058 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
1059 TString name = hashVariableName(indexSymbol->getSymbol());
1060 out << "for (int " << name << " = 0; "
1061 << name << " < 1; "
1062 << "++" << name << ")\n";
1063 }
1064 }
1065 else if (loopType == ELoopWhile) // while loop
1066 {
1067 out << "while (";
1068 ASSERT(node->getCondition() != NULL);
1069 node->getCondition()->traverse(this);
1070 out << ")\n";
1071 }
1072 else // do-while loop
1073 {
1074 ASSERT(loopType == ELoopDoWhile);
1075 out << "do\n";
1076 }
1077
1078 // Loop body.
1079 if (node->getUnrollFlag())
1080 {
1081 out << "{\n";
1082 mLoopUnrollStack.push(node);
1083 while (mLoopUnrollStack.satisfiesLoopCondition())
1084 {
1085 visitCodeBlock(node->getBody());
1086 mLoopUnrollStack.step();
1087 }
1088 mLoopUnrollStack.pop();
1089 out << "}\n";
1090 }
1091 else
1092 {
1093 visitCodeBlock(node->getBody());
1094 }
1095
1096 // Loop footer.
1097 if (loopType == ELoopDoWhile) // do-while loop
1098 {
1099 out << "while (";
1100 ASSERT(node->getCondition() != NULL);
1101 node->getCondition()->traverse(this);
1102 out << ");\n";
1103 }
1104 decrementDepth();
1105
1106 // No need to visit children. They have been already processed in
1107 // this function.
1108 return false;
1109}
1110
1111bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1112{
1113 switch (node->getFlowOp())
1114 {
1115 case EOpKill:
1116 writeTriplet(visit, "discard", NULL, NULL);
1117 break;
1118 case EOpBreak:
1119 writeTriplet(visit, "break", NULL, NULL);
1120 break;
1121 case EOpContinue:
1122 writeTriplet(visit, "continue", NULL, NULL);
1123 break;
1124 case EOpReturn:
1125 writeTriplet(visit, "return ", NULL, NULL);
1126 break;
1127 default:
1128 UNREACHABLE();
1129 }
1130
1131 return true;
1132}
1133
1134void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1135{
1136 TInfoSinkBase &out = objSink();
1137 if (node != NULL)
1138 {
1139 node->traverse(this);
1140 // Single statements not part of a sequence need to be terminated
1141 // with semi-colon.
1142 if (isSingleStatement(node))
1143 out << ";\n";
1144 }
1145 else
1146 {
1147 out << "{\n}\n"; // Empty code block.
1148 }
1149}
1150
1151TString TOutputGLSLBase::getTypeName(const TType &type)
1152{
1153 TInfoSinkBase out;
1154 if (type.isMatrix())
1155 {
1156 out << "mat";
1157 out << type.getNominalSize();
1158 }
1159 else if (type.isVector())
1160 {
1161 switch (type.getBasicType())
1162 {
1163 case EbtFloat:
1164 out << "vec";
1165 break;
1166 case EbtInt:
1167 out << "ivec";
1168 break;
1169 case EbtBool:
1170 out << "bvec";
1171 break;
1172 default:
1173 UNREACHABLE();
1174 }
1175 out << type.getNominalSize();
1176 }
1177 else
1178 {
1179 if (type.getBasicType() == EbtStruct)
1180 out << hashName(type.getStruct()->name());
1181 else
1182 out << type.getBasicString();
1183 }
1184 return TString(out.c_str());
1185}
1186
1187TString TOutputGLSLBase::hashName(const TString &name)
1188{
1189 if (mHashFunction == NULL || name.empty())
1190 return name;
1191 NameMap::const_iterator it = mNameMap.find(name.c_str());
1192 if (it != mNameMap.end())
1193 return it->second.c_str();
1194 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1195 mNameMap[name.c_str()] = hashedName.c_str();
1196 return hashedName;
1197}
1198
1199TString TOutputGLSLBase::hashVariableName(const TString &name)
1200{
1201 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
1202 return name;
1203 return hashName(name);
1204}
1205
1206TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
1207{
1208 TString name = TFunction::unmangleName(mangled_name);
1209 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
1210 return translateTextureFunction(name);
1211 return hashName(name);
1212}
1213
1214bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
1215{
1216 ASSERT(structure);
1217 if (structure->name().empty())
1218 {
1219 return false;
1220 }
1221
1222 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
1223}
1224
1225void TOutputGLSLBase::declareStruct(const TStructure *structure)
1226{
1227 TInfoSinkBase &out = objSink();
1228
1229 out << "struct " << hashName(structure->name()) << "{\n";
1230 const TFieldList &fields = structure->fields();
1231 for (size_t i = 0; i < fields.size(); ++i)
1232 {
1233 const TField *field = fields[i];
1234 if (writeVariablePrecision(field->type()->getPrecision()))
1235 out << " ";
1236 out << getTypeName(*field->type()) << " " << hashName(field->name());
1237 if (field->type()->isArray())
1238 out << arrayBrackets(*field->type());
1239 out << ";\n";
1240 }
1241 out << "}";
1242}
1243
1244