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.
7 #include "compiler/translator/OutputGLSLBase.h"
8 #include "compiler/translator/compilerdebug.h"
14 TString arrayBrackets(const TType &type)
16 ASSERT(type.isArray());
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
22 bool isSingleStatement(TIntermNode *node)
24 if (const TIntermAggregate *aggregate = node->getAsAggregate())
26 return (aggregate->getOp() != EOpFunction) &&
27 (aggregate->getOp() != EOpSequence);
29 else if (const TIntermSelection *selection = node->getAsSelectionNode())
31 // Ternary operators are usually part of an assignment operator.
32 // This handles those rare cases in which they are all by themselves.
33 return selection->usesTernaryOperator();
35 else if (node->getAsLoopNode())
43 TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
44 ShArrayIndexClampingStrategy clampingStrategy,
45 ShHashFunction64 hashFunction,
47 TSymbolTable &symbolTable,
49 : TIntermTraverser(true, true, true),
51 mDeclaringVariables(false),
52 mClampingStrategy(clampingStrategy),
53 mHashFunction(hashFunction),
55 mSymbolTable(symbolTable),
56 mShaderVersion(shaderVersion)
60 void TOutputGLSLBase::writeTriplet(
61 Visit visit, const char *preStr, const char *inStr, const char *postStr)
63 TInfoSinkBase &out = objSink();
64 if (visit == PreVisit && preStr)
66 else if (visit == InVisit && inStr)
68 else if (visit == PostVisit && postStr)
72 void TOutputGLSLBase::writeBuiltInFunctionTriplet(
73 Visit visit, const char *preStr, bool useEmulatedFunction)
75 TString preString = useEmulatedFunction ?
76 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
77 writeTriplet(visit, preString.c_str(), ", ", ")");
80 void TOutputGLSLBase::writeVariableType(const TType &type)
82 TInfoSinkBase &out = objSink();
83 TQualifier qualifier = type.getQualifier();
84 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
86 out << type.getQualifierString() << " ";
88 // Declare the struct if we have not done so already.
89 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
91 TStructure *structure = type.getStruct();
93 declareStruct(structure);
95 if (!structure->name().empty())
97 mDeclaredStructs.insert(structure->uniqueId());
102 if (writeVariablePrecision(type.getPrecision()))
104 out << getTypeName(type);
108 void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
110 TInfoSinkBase &out = objSink();
111 for (TIntermSequence::const_iterator iter = args.begin();
112 iter != args.end(); ++iter)
114 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
117 const TType &type = arg->getType();
118 writeVariableType(type);
120 const TString &name = arg->getSymbol();
122 out << " " << hashName(name);
124 out << arrayBrackets(type);
126 // Put a comma if this is not the last argument.
127 if (iter != args.end() - 1)
132 const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
133 const TType &type, const ConstantUnion *pConstUnion)
135 TInfoSinkBase &out = objSink();
137 if (type.getBasicType() == EbtStruct)
139 const TStructure *structure = type.getStruct();
140 out << hashName(structure->name()) << "(";
142 const TFieldList &fields = structure->fields();
143 for (size_t i = 0; i < fields.size(); ++i)
145 const TType *fieldType = fields[i]->type();
146 ASSERT(fieldType != NULL);
147 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
148 if (i != fields.size() - 1)
155 size_t size = type.getObjectSize();
156 bool writeType = size > 1;
158 out << getTypeName(type) << "(";
159 for (size_t i = 0; i < size; ++i, ++pConstUnion)
161 switch (pConstUnion->getType())
164 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
167 out << pConstUnion->getIConst();
170 out << pConstUnion->getBConst();
172 default: UNREACHABLE();
183 void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
185 TInfoSinkBase &out = objSink();
186 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
187 out << mLoopUnrollStack.getLoopIndexValue(node);
189 out << hashVariableName(node->getSymbol());
191 if (mDeclaringVariables && node->getType().isArray())
192 out << arrayBrackets(node->getType());
195 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
197 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
200 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
202 bool visitChildren = true;
203 TInfoSinkBase &out = objSink();
204 switch (node->getOp())
207 if (visit == InVisit)
210 // RHS of initialize is not being declared.
211 mDeclaringVariables = false;
215 writeTriplet(visit, "(", " = ", ")");
218 writeTriplet(visit, "(", " += ", ")");
221 writeTriplet(visit, "(", " -= ", ")");
224 writeTriplet(visit, "(", " /= ", ")");
226 // Notice the fall-through.
228 case EOpVectorTimesMatrixAssign:
229 case EOpVectorTimesScalarAssign:
230 case EOpMatrixTimesScalarAssign:
231 case EOpMatrixTimesMatrixAssign:
232 writeTriplet(visit, "(", " *= ", ")");
236 writeTriplet(visit, NULL, "[", "]");
238 case EOpIndexIndirect:
239 if (node->getAddIndexClamp())
241 if (visit == InVisit)
243 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
244 out << "[int(clamp(float(";
246 out << "[webgl_int_clamp(";
248 else if (visit == PostVisit)
251 TIntermTyped *left = node->getLeft();
252 TType leftType = left->getType();
256 // The shader will fail validation if the array length is not > 0.
257 maxSize = leftType.getArraySize() - 1;
261 maxSize = leftType.getNominalSize() - 1;
264 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
265 out << "), 0.0, float(" << maxSize << ")))]";
267 out << ", 0, " << maxSize << ")]";
272 writeTriplet(visit, NULL, "[", "]");
275 case EOpIndexDirectStruct:
276 if (visit == InVisit)
278 // Here we are writing out "foo.bar", where "foo" is struct
279 // and "bar" is field. In AST, it is represented as a binary
280 // node, where left child represents "foo" and right child "bar".
281 // The node itself represents ".". The struct field "bar" is
282 // actually stored as an index into TStructure::fields.
284 const TStructure *structure = node->getLeft()->getType().getStruct();
285 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
286 const TField *field = structure->fields()[index->getIConst(0)];
288 TString fieldName = field->name();
289 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
290 fieldName = hashName(fieldName);
293 visitChildren = false;
296 case EOpVectorSwizzle:
297 if (visit == InVisit)
300 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
301 TIntermSequence *sequence = rightChild->getSequence();
302 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
304 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
305 ASSERT(element->getBasicType() == EbtInt);
306 ASSERT(element->getNominalSize() == 1);
307 const ConstantUnion& data = element->getUnionArrayPointer()[0];
308 ASSERT(data.getType() == EbtInt);
309 switch (data.getIConst())
327 visitChildren = false;
332 writeTriplet(visit, "(", " + ", ")");
335 writeTriplet(visit, "(", " - ", ")");
338 writeTriplet(visit, "(", " * ", ")");
341 writeTriplet(visit, "(", " / ", ")");
347 writeTriplet(visit, "(", " == ", ")");
350 writeTriplet(visit, "(", " != ", ")");
353 writeTriplet(visit, "(", " < ", ")");
356 writeTriplet(visit, "(", " > ", ")");
358 case EOpLessThanEqual:
359 writeTriplet(visit, "(", " <= ", ")");
361 case EOpGreaterThanEqual:
362 writeTriplet(visit, "(", " >= ", ")");
365 // Notice the fall-through.
366 case EOpVectorTimesScalar:
367 case EOpVectorTimesMatrix:
368 case EOpMatrixTimesVector:
369 case EOpMatrixTimesScalar:
370 case EOpMatrixTimesMatrix:
371 writeTriplet(visit, "(", " * ", ")");
375 writeTriplet(visit, "(", " || ", ")");
378 writeTriplet(visit, "(", " ^^ ", ")");
381 writeTriplet(visit, "(", " && ", ")");
387 return visitChildren;
390 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
393 TString postString = ")";
395 switch (node->getOp())
397 case EOpNegative: preString = "(-"; break;
398 case EOpVectorLogicalNot: preString = "not("; break;
399 case EOpLogicalNot: preString = "(!"; break;
401 case EOpPostIncrement: preString = "("; postString = "++)"; break;
402 case EOpPostDecrement: preString = "("; postString = "--)"; break;
403 case EOpPreIncrement: preString = "(++"; break;
404 case EOpPreDecrement: preString = "(--"; break;
407 preString = "radians(";
410 preString = "degrees(";
447 preString = "inversesqrt(";
457 preString = "floor(";
463 preString = "fract(";
467 preString = "length(";
470 preString = "normalize(";
480 preString = "fwidth(";
494 if (visit == PreVisit && node->getUseEmulatedFunction())
495 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
496 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
501 bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
503 TInfoSinkBase &out = objSink();
505 if (node->usesTernaryOperator())
507 // Notice two brackets at the beginning and end. The outer ones
508 // encapsulate the whole ternary expression. This preserves the
509 // order of precedence when ternary expressions are used in a
510 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
512 node->getCondition()->traverse(this);
514 node->getTrueBlock()->traverse(this);
516 node->getFalseBlock()->traverse(this);
522 node->getCondition()->traverse(this);
525 incrementDepth(node);
526 visitCodeBlock(node->getTrueBlock());
528 if (node->getFalseBlock())
531 visitCodeBlock(node->getFalseBlock());
538 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
540 bool visitChildren = true;
541 TInfoSinkBase &out = objSink();
543 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
544 switch (node->getOp())
547 // Scope the sequences except when at the global scope.
553 incrementDepth(node);
554 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
555 iter != node->getSequence()->end(); ++iter)
557 TIntermNode *node = *iter;
558 ASSERT(node != NULL);
559 node->traverse(this);
561 if (isSingleStatement(node))
566 // Scope the sequences except when at the global scope.
571 visitChildren = false;
574 // Function declaration.
575 ASSERT(visit == PreVisit);
576 writeVariableType(node->getType());
577 out << " " << hashName(node->getName());
580 writeFunctionParameters(*(node->getSequence()));
583 visitChildren = false;
586 // Function definition.
587 ASSERT(visit == PreVisit);
588 writeVariableType(node->getType());
589 out << " " << hashFunctionName(node->getName());
591 incrementDepth(node);
592 // Function definition node contains one or two children nodes
593 // representing function parameters and function body. The latter
594 // is not present in case of empty function bodies.
595 const TIntermSequence &sequence = *(node->getSequence());
596 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
597 TIntermSequence::const_iterator seqIter = sequence.begin();
599 // Traverse function parameters.
600 TIntermAggregate *params = (*seqIter)->getAsAggregate();
601 ASSERT(params != NULL);
602 ASSERT(params->getOp() == EOpParameters);
603 params->traverse(this);
605 // Traverse function body.
606 TIntermAggregate *body = ++seqIter != sequence.end() ?
607 (*seqIter)->getAsAggregate() : NULL;
608 visitCodeBlock(body);
611 // Fully processed; no need to visit children.
612 visitChildren = false;
615 case EOpFunctionCall:
617 if (visit == PreVisit)
618 out << hashFunctionName(node->getName()) << "(";
619 else if (visit == InVisit)
625 // Function parameters.
626 ASSERT(visit == PreVisit);
628 writeFunctionParameters(*(node->getSequence()));
630 visitChildren = false;
633 // Variable declaration.
634 if (visit == PreVisit)
636 const TIntermSequence &sequence = *(node->getSequence());
637 const TIntermTyped *variable = sequence.front()->getAsTyped();
638 writeVariableType(variable->getType());
640 mDeclaringVariables = true;
642 else if (visit == InVisit)
645 mDeclaringVariables = true;
649 mDeclaringVariables = false;
652 case EOpInvariantDeclaration: {
653 // Invariant declaration.
654 ASSERT(visit == PreVisit);
655 const TIntermSequence *sequence = node->getSequence();
656 ASSERT(sequence && sequence->size() == 1);
657 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
659 out << "invariant " << symbol->getSymbol() << ";";
660 visitChildren = false;
663 case EOpConstructFloat:
664 writeTriplet(visit, "float(", NULL, ")");
666 case EOpConstructVec2:
667 writeBuiltInFunctionTriplet(visit, "vec2(", false);
669 case EOpConstructVec3:
670 writeBuiltInFunctionTriplet(visit, "vec3(", false);
672 case EOpConstructVec4:
673 writeBuiltInFunctionTriplet(visit, "vec4(", false);
675 case EOpConstructBool:
676 writeTriplet(visit, "bool(", NULL, ")");
678 case EOpConstructBVec2:
679 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
681 case EOpConstructBVec3:
682 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
684 case EOpConstructBVec4:
685 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
687 case EOpConstructInt:
688 writeTriplet(visit, "int(", NULL, ")");
690 case EOpConstructIVec2:
691 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
693 case EOpConstructIVec3:
694 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
696 case EOpConstructIVec4:
697 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
699 case EOpConstructMat2:
700 writeBuiltInFunctionTriplet(visit, "mat2(", false);
702 case EOpConstructMat3:
703 writeBuiltInFunctionTriplet(visit, "mat3(", false);
705 case EOpConstructMat4:
706 writeBuiltInFunctionTriplet(visit, "mat4(", false);
708 case EOpConstructStruct:
709 if (visit == PreVisit)
711 const TType &type = node->getType();
712 ASSERT(type.getBasicType() == EbtStruct);
713 out << hashName(type.getStruct()->name()) << "(";
715 else if (visit == InVisit)
726 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
729 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
731 case EOpLessThanEqual:
732 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
734 case EOpGreaterThanEqual:
735 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
738 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
740 case EOpVectorNotEqual:
741 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
744 writeTriplet(visit, NULL, ", ", NULL);
748 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
751 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
754 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
757 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
760 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
763 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
766 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
769 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
772 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
775 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
778 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
781 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
784 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
787 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
790 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
793 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
799 return visitChildren;
802 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
804 TInfoSinkBase &out = objSink();
806 incrementDepth(node);
808 TLoopType loopType = node->getType();
809 if (loopType == ELoopFor) // for loop
811 if (!node->getUnrollFlag())
815 node->getInit()->traverse(this);
818 if (node->getCondition())
819 node->getCondition()->traverse(this);
822 if (node->getExpression())
823 node->getExpression()->traverse(this);
828 // Need to put a one-iteration loop here to handle break.
829 TIntermSequence *declSeq =
830 node->getInit()->getAsAggregate()->getSequence();
831 TIntermSymbol *indexSymbol =
832 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
833 TString name = hashVariableName(indexSymbol->getSymbol());
834 out << "for (int " << name << " = 0; "
836 << "++" << name << ")\n";
839 else if (loopType == ELoopWhile) // while loop
842 ASSERT(node->getCondition() != NULL);
843 node->getCondition()->traverse(this);
846 else // do-while loop
848 ASSERT(loopType == ELoopDoWhile);
853 if (node->getUnrollFlag())
856 mLoopUnrollStack.push(node);
857 while (mLoopUnrollStack.satisfiesLoopCondition())
859 visitCodeBlock(node->getBody());
860 mLoopUnrollStack.step();
862 mLoopUnrollStack.pop();
867 visitCodeBlock(node->getBody());
871 if (loopType == ELoopDoWhile) // do-while loop
874 ASSERT(node->getCondition() != NULL);
875 node->getCondition()->traverse(this);
880 // No need to visit children. They have been already processed in
885 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
887 switch (node->getFlowOp())
890 writeTriplet(visit, "discard", NULL, NULL);
893 writeTriplet(visit, "break", NULL, NULL);
896 writeTriplet(visit, "continue", NULL, NULL);
899 writeTriplet(visit, "return ", NULL, NULL);
908 void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
910 TInfoSinkBase &out = objSink();
913 node->traverse(this);
914 // Single statements not part of a sequence need to be terminated
916 if (isSingleStatement(node))
921 out << "{\n}\n"; // Empty code block.
925 TString TOutputGLSLBase::getTypeName(const TType &type)
931 out << type.getNominalSize();
933 else if (type.isVector())
935 switch (type.getBasicType())
949 out << type.getNominalSize();
953 if (type.getBasicType() == EbtStruct)
954 out << hashName(type.getStruct()->name());
956 out << type.getBasicString();
958 return TString(out.c_str());
961 TString TOutputGLSLBase::hashName(const TString &name)
963 if (mHashFunction == NULL || name.empty())
965 NameMap::const_iterator it = mNameMap.find(name.c_str());
966 if (it != mNameMap.end())
967 return it->second.c_str();
968 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
969 mNameMap[name.c_str()] = hashedName.c_str();
973 TString TOutputGLSLBase::hashVariableName(const TString &name)
975 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
977 return hashName(name);
980 TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
982 TString name = TFunction::unmangleName(mangled_name);
983 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
984 return translateTextureFunction(name);
985 return hashName(name);
988 bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
991 if (structure->name().empty())
996 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
999 void TOutputGLSLBase::declareStruct(const TStructure *structure)
1001 TInfoSinkBase &out = objSink();
1003 out << "struct " << hashName(structure->name()) << "{\n";
1004 const TFieldList &fields = structure->fields();
1005 for (size_t i = 0; i < fields.size(); ++i)
1007 const TField *field = fields[i];
1008 if (writeVariablePrecision(field->type()->getPrecision()))
1010 out << getTypeName(*field->type()) << " " << hashName(field->name());
1011 if (field->type()->isArray())
1012 out << arrayBrackets(*field->type());