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