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