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