1 //
2 // Copyright 2002 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 else if (node->getAsPreprocessorDirective())
50 {
51 return false;
52 }
53 return true;
54 }
55
56 class CommaSeparatedListItemPrefixGenerator
57 {
58 public:
CommaSeparatedListItemPrefixGenerator()59 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
60
61 private:
62 bool mFirst;
63
64 template <typename Stream>
65 friend Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen);
66 };
67
68 template <typename Stream>
operator <<(Stream & out,CommaSeparatedListItemPrefixGenerator & gen)69 Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen)
70 {
71 if (gen.mFirst)
72 {
73 gen.mFirst = false;
74 }
75 else
76 {
77 out << ", ";
78 }
79 return out;
80 }
81
82 } // namespace
83
TOutputGLSLBase(TInfoSinkBase & objSink,ShHashFunction64 hashFunction,NameMap & nameMap,TSymbolTable * symbolTable,sh::GLenum shaderType,int shaderVersion,ShShaderOutput output,ShCompileOptions compileOptions)84 TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
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 mHashFunction(hashFunction),
96 mNameMap(nameMap),
97 mShaderType(shaderType),
98 mShaderVersion(shaderVersion),
99 mOutput(output),
100 mCompileOptions(compileOptions)
101 {}
102
writeInvariantQualifier(const TType & type)103 void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
104 {
105 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
106 {
107 TInfoSinkBase &out = objSink();
108 out << "invariant ";
109 }
110 }
111
writePreciseQualifier(const TType & type)112 void TOutputGLSLBase::writePreciseQualifier(const TType &type)
113 {
114 TInfoSinkBase &out = objSink();
115 out << "precise ";
116 }
117
writeFloat(TInfoSinkBase & out,float f)118 void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
119 {
120 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
121 {
122 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
123 }
124 else
125 {
126 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
127 }
128 }
129
writeTriplet(Visit visit,const char * preStr,const char * inStr,const char * postStr)130 void TOutputGLSLBase::writeTriplet(Visit visit,
131 const char *preStr,
132 const char *inStr,
133 const char *postStr)
134 {
135 TInfoSinkBase &out = objSink();
136 if (visit == PreVisit && preStr)
137 out << preStr;
138 else if (visit == InVisit && inStr)
139 out << inStr;
140 else if (visit == PostVisit && postStr)
141 out << postStr;
142 }
143
writeFunctionTriplet(Visit visit,const ImmutableString & functionName,bool useEmulatedFunction)144 void TOutputGLSLBase::writeFunctionTriplet(Visit visit,
145 const ImmutableString &functionName,
146 bool useEmulatedFunction)
147 {
148 TInfoSinkBase &out = objSink();
149 if (visit == PreVisit)
150 {
151 if (useEmulatedFunction)
152 {
153 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, functionName.data());
154 }
155 else
156 {
157 out << functionName;
158 }
159 out << "(";
160 }
161 else
162 {
163 writeTriplet(visit, nullptr, ", ", ")");
164 }
165 }
166
167 // Outputs what goes inside layout(), except for location and binding qualifiers, as they are
168 // handled differently between GL GLSL and Vulkan GLSL.
getCommonLayoutQualifiers(TIntermSymbol * variable)169 std::string TOutputGLSLBase::getCommonLayoutQualifiers(TIntermSymbol *variable)
170 {
171 std::ostringstream out;
172 CommaSeparatedListItemPrefixGenerator listItemPrefix;
173
174 const TType &type = variable->getType();
175 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
176
177 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
178 IsVarying(type.getQualifier()))
179 {
180 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0)
181 {
182 out << listItemPrefix << "index = " << layoutQualifier.index;
183 }
184 }
185
186 if (type.getQualifier() == EvqFragmentOut)
187 {
188 if (layoutQualifier.yuv == true)
189 {
190 out << listItemPrefix << "yuv";
191 }
192 }
193
194 if (IsImage(type.getBasicType()))
195 {
196 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
197 {
198 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
199 out << listItemPrefix
200 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
201 }
202 }
203
204 if (IsAtomicCounter(type.getBasicType()))
205 {
206 out << listItemPrefix << "offset = " << layoutQualifier.offset;
207 }
208
209 return out.str();
210 }
211
212 // Outputs memory qualifiers applied to images, buffers and its fields, as well as image function
213 // arguments.
getMemoryQualifiers(const TType & type)214 std::string TOutputGLSLBase::getMemoryQualifiers(const TType &type)
215 {
216 std::ostringstream out;
217
218 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
219 if (memoryQualifier.readonly)
220 {
221 out << "readonly ";
222 }
223
224 if (memoryQualifier.writeonly)
225 {
226 out << "writeonly ";
227 }
228
229 if (memoryQualifier.coherent)
230 {
231 out << "coherent ";
232 }
233
234 if (memoryQualifier.restrictQualifier)
235 {
236 out << "restrict ";
237 }
238
239 if (memoryQualifier.volatileQualifier)
240 {
241 out << "volatile ";
242 }
243
244 return out.str();
245 }
246
writeLayoutQualifier(TIntermSymbol * variable)247 void TOutputGLSLBase::writeLayoutQualifier(TIntermSymbol *variable)
248 {
249 const TType &type = variable->getType();
250
251 if (!NeedsToWriteLayoutQualifier(type))
252 {
253 return;
254 }
255
256 if (type.getBasicType() == EbtInterfaceBlock)
257 {
258 declareInterfaceBlockLayout(type);
259 return;
260 }
261
262 TInfoSinkBase &out = objSink();
263 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
264 out << "layout(";
265
266 CommaSeparatedListItemPrefixGenerator listItemPrefix;
267
268 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
269 IsVarying(type.getQualifier()))
270 {
271 if (layoutQualifier.location >= 0)
272 {
273 out << listItemPrefix << "location = " << layoutQualifier.location;
274 }
275 }
276
277 if (IsOpaqueType(type.getBasicType()))
278 {
279 if (layoutQualifier.binding >= 0)
280 {
281 out << listItemPrefix << "binding = " << layoutQualifier.binding;
282 }
283 }
284
285 std::string otherQualifiers = getCommonLayoutQualifiers(variable);
286 if (!otherQualifiers.empty())
287 {
288 out << listItemPrefix << otherQualifiers;
289 }
290
291 out << ") ";
292 }
293
writeFieldLayoutQualifier(const TField * field)294 void TOutputGLSLBase::writeFieldLayoutQualifier(const TField *field)
295 {
296 if (!field->type()->isMatrix() && !field->type()->isStructureContainingMatrices())
297 {
298 return;
299 }
300
301 TInfoSinkBase &out = objSink();
302
303 out << "layout(";
304 switch (field->type()->getLayoutQualifier().matrixPacking)
305 {
306 case EmpUnspecified:
307 case EmpColumnMajor:
308 // Default matrix packing is column major.
309 out << "column_major";
310 break;
311
312 case EmpRowMajor:
313 out << "row_major";
314 break;
315
316 default:
317 UNREACHABLE();
318 break;
319 }
320 out << ") ";
321 }
322
writeQualifier(TQualifier qualifier,const TType & type,const TSymbol * symbol)323 void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol)
324 {
325 const char *result = mapQualifierToString(qualifier);
326 if (result && result[0] != '\0')
327 {
328 objSink() << result << " ";
329 }
330
331 objSink() << getMemoryQualifiers(type);
332 }
333
mapQualifierToString(TQualifier qualifier)334 const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
335 {
336 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
337 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
338 {
339 switch (qualifier)
340 {
341 // The return string is consistent with sh::getQualifierString() from
342 // BaseTypes.h minus the "centroid" keyword.
343 case EvqCentroid:
344 return "";
345 case EvqCentroidIn:
346 return "smooth in";
347 case EvqCentroidOut:
348 return "smooth out";
349 default:
350 break;
351 }
352 }
353 if (sh::IsGLSL130OrNewer(mOutput))
354 {
355 switch (qualifier)
356 {
357 case EvqAttribute:
358 return "in";
359 case EvqVaryingIn:
360 return "in";
361 case EvqVaryingOut:
362 return "out";
363 default:
364 break;
365 }
366 }
367 return sh::getQualifierString(qualifier);
368 }
369
writeVariableType(const TType & type,const TSymbol * symbol,bool isFunctionArgument)370 void TOutputGLSLBase::writeVariableType(const TType &type,
371 const TSymbol *symbol,
372 bool isFunctionArgument)
373 {
374 TQualifier qualifier = type.getQualifier();
375 TInfoSinkBase &out = objSink();
376 if (type.isInvariant())
377 {
378 writeInvariantQualifier(type);
379 }
380 if (type.isPrecise())
381 {
382 writePreciseQualifier(type);
383 }
384 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
385 {
386 writeQualifier(qualifier, type, symbol);
387 }
388 if (isFunctionArgument)
389 {
390 // Function arguments are the only place (other than image/SSBO/field declaration) where
391 // memory qualifiers can appear.
392 out << getMemoryQualifiers(type);
393 }
394
395 // Declare the struct.
396 if (type.isStructSpecifier())
397 {
398 const TStructure *structure = type.getStruct();
399
400 declareStruct(structure);
401 }
402 else if (type.getBasicType() == EbtInterfaceBlock)
403 {
404 declareInterfaceBlock(type);
405 }
406 else
407 {
408 if (writeVariablePrecision(type.getPrecision()))
409 out << " ";
410 out << getTypeName(type);
411 }
412 }
413
writeFunctionParameters(const TFunction * func)414 void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
415 {
416 TInfoSinkBase &out = objSink();
417 size_t paramCount = func->getParamCount();
418 for (size_t i = 0; i < paramCount; ++i)
419 {
420 const TVariable *param = func->getParam(i);
421 const TType &type = param->getType();
422 writeVariableType(type, param, true);
423
424 if (param->symbolType() != SymbolType::Empty)
425 out << " " << hashName(param);
426 if (type.isArray())
427 out << ArrayString(type);
428
429 // Put a comma if this is not the last argument.
430 if (i != paramCount - 1)
431 out << ", ";
432 }
433 }
434
writeConstantUnion(const TType & type,const TConstantUnion * pConstUnion)435 const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
436 const TConstantUnion *pConstUnion)
437 {
438 TInfoSinkBase &out = objSink();
439
440 if (type.getBasicType() == EbtStruct)
441 {
442 const TStructure *structure = type.getStruct();
443 out << hashName(structure) << "(";
444
445 const TFieldList &fields = structure->fields();
446 for (size_t i = 0; i < fields.size(); ++i)
447 {
448 const TType *fieldType = fields[i]->type();
449 ASSERT(fieldType != nullptr);
450 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
451 if (i != fields.size() - 1)
452 out << ", ";
453 }
454 out << ")";
455 }
456 else
457 {
458 size_t size = type.getObjectSize();
459 bool writeType = size > 1;
460 if (writeType)
461 out << getTypeName(type) << "(";
462 for (size_t i = 0; i < size; ++i, ++pConstUnion)
463 {
464 switch (pConstUnion->getType())
465 {
466 case EbtFloat:
467 writeFloat(out, pConstUnion->getFConst());
468 break;
469 case EbtInt:
470 out << pConstUnion->getIConst();
471 break;
472 case EbtUInt:
473 out << pConstUnion->getUConst() << "u";
474 break;
475 case EbtBool:
476 out << pConstUnion->getBConst();
477 break;
478 case EbtYuvCscStandardEXT:
479 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
480 break;
481 default:
482 UNREACHABLE();
483 }
484 if (i != size - 1)
485 out << ", ";
486 }
487 if (writeType)
488 out << ")";
489 }
490 return pConstUnion;
491 }
492
writeConstructorTriplet(Visit visit,const TType & type)493 void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
494 {
495 TInfoSinkBase &out = objSink();
496 if (visit == PreVisit)
497 {
498 if (type.isArray())
499 {
500 out << getTypeName(type);
501 out << ArrayString(type);
502 out << "(";
503 }
504 else
505 {
506 out << getTypeName(type) << "(";
507 }
508 }
509 else
510 {
511 writeTriplet(visit, nullptr, ", ", ")");
512 }
513 }
514
visitSymbol(TIntermSymbol * node)515 void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
516 {
517 TInfoSinkBase &out = objSink();
518 out << hashName(&node->variable());
519
520 if (mDeclaringVariable && node->getType().isArray())
521 out << ArrayString(node->getType());
522 }
523
visitConstantUnion(TIntermConstantUnion * node)524 void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
525 {
526 writeConstantUnion(node->getType(), node->getConstantValue());
527 }
528
visitSwizzle(Visit visit,TIntermSwizzle * node)529 bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
530 {
531 TInfoSinkBase &out = objSink();
532 if (visit == PostVisit)
533 {
534 out << ".";
535 node->writeOffsetsAsXYZW(&out);
536 }
537 return true;
538 }
539
visitBinary(Visit visit,TIntermBinary * node)540 bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
541 {
542 bool visitChildren = true;
543 TInfoSinkBase &out = objSink();
544 switch (node->getOp())
545 {
546 case EOpComma:
547 writeTriplet(visit, "(", ", ", ")");
548 break;
549 case EOpInitialize:
550 if (visit == InVisit)
551 {
552 out << " = ";
553 // RHS of initialize is not being declared.
554 mDeclaringVariable = false;
555 }
556 break;
557 case EOpAssign:
558 writeTriplet(visit, "(", " = ", ")");
559 break;
560 case EOpAddAssign:
561 writeTriplet(visit, "(", " += ", ")");
562 break;
563 case EOpSubAssign:
564 writeTriplet(visit, "(", " -= ", ")");
565 break;
566 case EOpDivAssign:
567 writeTriplet(visit, "(", " /= ", ")");
568 break;
569 case EOpIModAssign:
570 writeTriplet(visit, "(", " %= ", ")");
571 break;
572 // Notice the fall-through.
573 case EOpMulAssign:
574 case EOpVectorTimesMatrixAssign:
575 case EOpVectorTimesScalarAssign:
576 case EOpMatrixTimesScalarAssign:
577 case EOpMatrixTimesMatrixAssign:
578 writeTriplet(visit, "(", " *= ", ")");
579 break;
580 case EOpBitShiftLeftAssign:
581 writeTriplet(visit, "(", " <<= ", ")");
582 break;
583 case EOpBitShiftRightAssign:
584 writeTriplet(visit, "(", " >>= ", ")");
585 break;
586 case EOpBitwiseAndAssign:
587 writeTriplet(visit, "(", " &= ", ")");
588 break;
589 case EOpBitwiseXorAssign:
590 writeTriplet(visit, "(", " ^= ", ")");
591 break;
592 case EOpBitwiseOrAssign:
593 writeTriplet(visit, "(", " |= ", ")");
594 break;
595
596 case EOpIndexDirect:
597 case EOpIndexIndirect:
598 writeTriplet(visit, nullptr, "[", "]");
599 break;
600 case EOpIndexDirectStruct:
601 if (visit == InVisit)
602 {
603 // Here we are writing out "foo.bar", where "foo" is struct
604 // and "bar" is field. In AST, it is represented as a binary
605 // node, where left child represents "foo" and right child "bar".
606 // The node itself represents ".". The struct field "bar" is
607 // actually stored as an index into TStructure::fields.
608 out << ".";
609 const TStructure *structure = node->getLeft()->getType().getStruct();
610 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
611 const TField *field = structure->fields()[index->getIConst(0)];
612
613 out << hashFieldName(field);
614 visitChildren = false;
615 }
616 break;
617 case EOpIndexDirectInterfaceBlock:
618 if (visit == InVisit)
619 {
620 out << ".";
621 const TInterfaceBlock *interfaceBlock =
622 node->getLeft()->getType().getInterfaceBlock();
623 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
624 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
625 out << hashFieldName(field);
626 visitChildren = false;
627 }
628 break;
629
630 case EOpAdd:
631 writeTriplet(visit, "(", " + ", ")");
632 break;
633 case EOpSub:
634 writeTriplet(visit, "(", " - ", ")");
635 break;
636 case EOpMul:
637 writeTriplet(visit, "(", " * ", ")");
638 break;
639 case EOpDiv:
640 writeTriplet(visit, "(", " / ", ")");
641 break;
642 case EOpIMod:
643 writeTriplet(visit, "(", " % ", ")");
644 break;
645 case EOpBitShiftLeft:
646 writeTriplet(visit, "(", " << ", ")");
647 break;
648 case EOpBitShiftRight:
649 writeTriplet(visit, "(", " >> ", ")");
650 break;
651 case EOpBitwiseAnd:
652 writeTriplet(visit, "(", " & ", ")");
653 break;
654 case EOpBitwiseXor:
655 writeTriplet(visit, "(", " ^ ", ")");
656 break;
657 case EOpBitwiseOr:
658 writeTriplet(visit, "(", " | ", ")");
659 break;
660
661 case EOpEqual:
662 writeTriplet(visit, "(", " == ", ")");
663 break;
664 case EOpNotEqual:
665 writeTriplet(visit, "(", " != ", ")");
666 break;
667 case EOpLessThan:
668 writeTriplet(visit, "(", " < ", ")");
669 break;
670 case EOpGreaterThan:
671 writeTriplet(visit, "(", " > ", ")");
672 break;
673 case EOpLessThanEqual:
674 writeTriplet(visit, "(", " <= ", ")");
675 break;
676 case EOpGreaterThanEqual:
677 writeTriplet(visit, "(", " >= ", ")");
678 break;
679
680 // Notice the fall-through.
681 case EOpVectorTimesScalar:
682 case EOpVectorTimesMatrix:
683 case EOpMatrixTimesVector:
684 case EOpMatrixTimesScalar:
685 case EOpMatrixTimesMatrix:
686 writeTriplet(visit, "(", " * ", ")");
687 break;
688
689 case EOpLogicalOr:
690 writeTriplet(visit, "(", " || ", ")");
691 break;
692 case EOpLogicalXor:
693 writeTriplet(visit, "(", " ^^ ", ")");
694 break;
695 case EOpLogicalAnd:
696 writeTriplet(visit, "(", " && ", ")");
697 break;
698 default:
699 UNREACHABLE();
700 }
701
702 return visitChildren;
703 }
704
visitUnary(Visit visit,TIntermUnary * node)705 bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
706 {
707 const char *preString = "";
708 const char *postString = ")";
709
710 switch (node->getOp())
711 {
712 case EOpNegative:
713 preString = "(-";
714 break;
715 case EOpPositive:
716 preString = "(+";
717 break;
718 case EOpLogicalNot:
719 preString = "(!";
720 break;
721 case EOpBitwiseNot:
722 preString = "(~";
723 break;
724
725 case EOpPostIncrement:
726 preString = "(";
727 postString = "++)";
728 break;
729 case EOpPostDecrement:
730 preString = "(";
731 postString = "--)";
732 break;
733 case EOpPreIncrement:
734 preString = "(++";
735 break;
736 case EOpPreDecrement:
737 preString = "(--";
738 break;
739 case EOpArrayLength:
740 preString = "((";
741 postString = ").length())";
742 break;
743
744 default:
745 writeFunctionTriplet(visit, node->getFunction()->name(),
746 node->getUseEmulatedFunction());
747 return true;
748 }
749
750 writeTriplet(visit, preString, nullptr, postString);
751
752 return true;
753 }
754
visitTernary(Visit visit,TIntermTernary * node)755 bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
756 {
757 TInfoSinkBase &out = objSink();
758 // Notice two brackets at the beginning and end. The outer ones
759 // encapsulate the whole ternary expression. This preserves the
760 // order of precedence when ternary expressions are used in a
761 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
762 out << "((";
763 node->getCondition()->traverse(this);
764 out << ") ? (";
765 node->getTrueExpression()->traverse(this);
766 out << ") : (";
767 node->getFalseExpression()->traverse(this);
768 out << "))";
769 return false;
770 }
771
visitIfElse(Visit visit,TIntermIfElse * node)772 bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
773 {
774 TInfoSinkBase &out = objSink();
775
776 out << "if (";
777 node->getCondition()->traverse(this);
778 out << ")\n";
779
780 visitCodeBlock(node->getTrueBlock());
781
782 if (node->getFalseBlock())
783 {
784 out << "else\n";
785 visitCodeBlock(node->getFalseBlock());
786 }
787 return false;
788 }
789
visitSwitch(Visit visit,TIntermSwitch * node)790 bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
791 {
792 ASSERT(node->getStatementList());
793 writeTriplet(visit, "switch (", ") ", nullptr);
794 // The curly braces get written when visiting the statementList aggregate
795 return true;
796 }
797
visitCase(Visit visit,TIntermCase * node)798 bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
799 {
800 if (node->hasCondition())
801 {
802 writeTriplet(visit, "case (", nullptr, "):\n");
803 return true;
804 }
805 else
806 {
807 TInfoSinkBase &out = objSink();
808 out << "default:\n";
809 return false;
810 }
811 }
812
visitBlock(Visit visit,TIntermBlock * node)813 bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
814 {
815 TInfoSinkBase &out = objSink();
816 // Scope the blocks except when at the global scope.
817 if (getCurrentTraversalDepth() > 0)
818 {
819 out << "{\n";
820 }
821
822 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
823 iter != node->getSequence()->end(); ++iter)
824 {
825 TIntermNode *curNode = *iter;
826 ASSERT(curNode != nullptr);
827 curNode->traverse(this);
828
829 if (isSingleStatement(curNode))
830 out << ";\n";
831 }
832
833 // Scope the blocks except when at the global scope.
834 if (getCurrentTraversalDepth() > 0)
835 {
836 out << "}\n";
837 }
838 return false;
839 }
840
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)841 bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
842 {
843 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
844 prototype->traverse(this);
845 visitCodeBlock(node->getBody());
846
847 // Fully processed; no need to visit children.
848 return false;
849 }
850
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)851 bool TOutputGLSLBase::visitGlobalQualifierDeclaration(Visit visit,
852 TIntermGlobalQualifierDeclaration *node)
853 {
854 TInfoSinkBase &out = objSink();
855 ASSERT(visit == PreVisit);
856 const TIntermSymbol *symbol = node->getSymbol();
857 out << (node->isPrecise() ? "precise " : "invariant ") << hashName(&symbol->variable());
858 return false;
859 }
860
visitFunctionPrototype(TIntermFunctionPrototype * node)861 void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
862 {
863 TInfoSinkBase &out = objSink();
864
865 const TType &type = node->getType();
866 writeVariableType(type, node->getFunction(), false);
867 if (type.isArray())
868 out << ArrayString(type);
869
870 out << " " << hashFunctionNameIfNeeded(node->getFunction());
871
872 out << "(";
873 writeFunctionParameters(node->getFunction());
874 out << ")";
875 }
876
visitAggregate(Visit visit,TIntermAggregate * node)877 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
878 {
879 bool visitChildren = true;
880 if (node->getOp() == EOpConstruct)
881 {
882 writeConstructorTriplet(visit, node->getType());
883 }
884 else
885 {
886 // Function call.
887 ImmutableString functionName = node->getFunction()->name();
888 if (visit == PreVisit)
889 {
890 if (node->getOp() == EOpCallFunctionInAST ||
891 node->getOp() == EOpCallInternalRawFunction)
892 {
893 functionName = hashFunctionNameIfNeeded(node->getFunction());
894 }
895 else
896 {
897 functionName =
898 translateTextureFunction(node->getFunction()->name(), mCompileOptions);
899 }
900 }
901 writeFunctionTriplet(visit, functionName, node->getUseEmulatedFunction());
902 }
903 return visitChildren;
904 }
905
visitDeclaration(Visit visit,TIntermDeclaration * node)906 bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
907 {
908 TInfoSinkBase &out = objSink();
909
910 // Variable declaration.
911 if (visit == PreVisit)
912 {
913 const TIntermSequence &sequence = *(node->getSequence());
914 TIntermTyped *variable = sequence.front()->getAsTyped();
915 TIntermSymbol *symbolNode = variable->getAsSymbolNode();
916 if (symbolNode == nullptr)
917 {
918 ASSERT(variable->getAsBinaryNode() &&
919 variable->getAsBinaryNode()->getOp() == EOpInitialize);
920 symbolNode = variable->getAsBinaryNode()->getLeft()->getAsSymbolNode();
921 }
922 ASSERT(symbolNode);
923
924 if (symbolNode->getName() != "gl_ClipDistance" &&
925 symbolNode->getName() != "gl_CullDistance")
926 {
927 // gl_Clip/CullDistance re-declaration doesn't need layout.
928 writeLayoutQualifier(symbolNode);
929 }
930
931 // Note: the TIntermDeclaration type is used for variable declaration instead of the
932 // TIntermSymbol one. The TIntermDeclaration type includes precision promotions from the
933 // right hand side that the symbol may be missing. This is an inconsistency in the tree
934 // that is too ingrained.
935 writeVariableType(variable->getType(), &symbolNode->variable(), false);
936 if (symbolNode->variable().symbolType() != SymbolType::Empty)
937 {
938 out << " ";
939 }
940 mDeclaringVariable = true;
941 }
942 else if (visit == InVisit)
943 {
944 UNREACHABLE();
945 }
946 else
947 {
948 mDeclaringVariable = false;
949 }
950 return true;
951 }
952
visitLoop(Visit visit,TIntermLoop * node)953 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
954 {
955 TInfoSinkBase &out = objSink();
956
957 TLoopType loopType = node->getType();
958
959 if (loopType == ELoopFor) // for loop
960 {
961 out << "for (";
962 if (node->getInit())
963 node->getInit()->traverse(this);
964 out << "; ";
965
966 if (node->getCondition())
967 node->getCondition()->traverse(this);
968 out << "; ";
969
970 if (node->getExpression())
971 node->getExpression()->traverse(this);
972 out << ")\n";
973
974 visitCodeBlock(node->getBody());
975 }
976 else if (loopType == ELoopWhile) // while loop
977 {
978 out << "while (";
979 ASSERT(node->getCondition() != nullptr);
980 node->getCondition()->traverse(this);
981 out << ")\n";
982
983 visitCodeBlock(node->getBody());
984 }
985 else // do-while loop
986 {
987 ASSERT(loopType == ELoopDoWhile);
988 out << "do\n";
989
990 visitCodeBlock(node->getBody());
991
992 out << "while (";
993 ASSERT(node->getCondition() != nullptr);
994 node->getCondition()->traverse(this);
995 out << ");\n";
996 }
997
998 // No need to visit children. They have been already processed in
999 // this function.
1000 return false;
1001 }
1002
visitBranch(Visit visit,TIntermBranch * node)1003 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1004 {
1005 switch (node->getFlowOp())
1006 {
1007 case EOpKill:
1008 writeTriplet(visit, "discard", nullptr, nullptr);
1009 break;
1010 case EOpBreak:
1011 writeTriplet(visit, "break", nullptr, nullptr);
1012 break;
1013 case EOpContinue:
1014 writeTriplet(visit, "continue", nullptr, nullptr);
1015 break;
1016 case EOpReturn:
1017 writeTriplet(visit, "return ", nullptr, nullptr);
1018 break;
1019 default:
1020 UNREACHABLE();
1021 }
1022
1023 return true;
1024 }
1025
visitCodeBlock(TIntermBlock * node)1026 void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1027 {
1028 TInfoSinkBase &out = objSink();
1029 if (node != nullptr)
1030 {
1031 node->traverse(this);
1032 // Single statements not part of a sequence need to be terminated
1033 // with semi-colon.
1034 if (isSingleStatement(node))
1035 out << ";\n";
1036 }
1037 else
1038 {
1039 out << "{\n}\n"; // Empty code block.
1040 }
1041 }
1042
visitPreprocessorDirective(TIntermPreprocessorDirective * node)1043 void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1044 {
1045 TInfoSinkBase &out = objSink();
1046
1047 out << "\n";
1048
1049 switch (node->getDirective())
1050 {
1051 case PreprocessorDirective::Define:
1052 out << "#define";
1053 break;
1054 case PreprocessorDirective::Endif:
1055 out << "#endif";
1056 break;
1057 case PreprocessorDirective::If:
1058 out << "#if";
1059 break;
1060 case PreprocessorDirective::Ifdef:
1061 out << "#ifdef";
1062 break;
1063
1064 default:
1065 UNREACHABLE();
1066 break;
1067 }
1068
1069 if (!node->getCommand().empty())
1070 {
1071 out << " " << node->getCommand();
1072 }
1073
1074 out << "\n";
1075 }
1076
getTypeName(const TType & type)1077 ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
1078 {
1079 if (type.getBasicType() == EbtSamplerVideoWEBGL)
1080 {
1081 // TODO(http://anglebug.com/3889): translate SamplerVideoWEBGL into different token
1082 // when necessary (e.g. on Android devices)
1083 return ImmutableString("sampler2D");
1084 }
1085
1086 return GetTypeName(type, mHashFunction, &mNameMap);
1087 }
1088
hashName(const TSymbol * symbol)1089 ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
1090 {
1091 return HashName(symbol, mHashFunction, &mNameMap);
1092 }
1093
hashFieldName(const TField * field)1094 ImmutableString TOutputGLSLBase::hashFieldName(const TField *field)
1095 {
1096 ASSERT(field->symbolType() != SymbolType::Empty);
1097 if (field->symbolType() == SymbolType::UserDefined)
1098 {
1099 return HashName(field->name(), mHashFunction, &mNameMap);
1100 }
1101
1102 return field->name();
1103 }
1104
hashFunctionNameIfNeeded(const TFunction * func)1105 ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
1106 {
1107 if (func->isMain())
1108 {
1109 return func->name();
1110 }
1111 else
1112 {
1113 return hashName(func);
1114 }
1115 }
1116
declareStruct(const TStructure * structure)1117 void TOutputGLSLBase::declareStruct(const TStructure *structure)
1118 {
1119 TInfoSinkBase &out = objSink();
1120
1121 out << "struct ";
1122
1123 if (structure->symbolType() != SymbolType::Empty)
1124 {
1125 out << hashName(structure) << " ";
1126 }
1127 out << "{\n";
1128 const TFieldList &fields = structure->fields();
1129 for (size_t i = 0; i < fields.size(); ++i)
1130 {
1131 const TField *field = fields[i];
1132 if (writeVariablePrecision(field->type()->getPrecision()))
1133 out << " ";
1134 out << getTypeName(*field->type()) << " " << hashFieldName(field);
1135 if (field->type()->isArray())
1136 out << ArrayString(*field->type());
1137 out << ";\n";
1138 }
1139 out << "}";
1140 }
1141
declareInterfaceBlockLayout(const TType & type)1142 void TOutputGLSLBase::declareInterfaceBlockLayout(const TType &type)
1143 {
1144 // 4.4.5 Uniform and Shader Storage Block Layout Qualifiers in GLSL 4.5 spec.
1145 // Layout qualifiers can be used for uniform and shader storage blocks,
1146 // but not for non-block uniform declarations.
1147 if (IsShaderIoBlock(type.getQualifier()))
1148 {
1149 return;
1150 }
1151
1152 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1153 TInfoSinkBase &out = objSink();
1154
1155 out << "layout(";
1156
1157 switch (interfaceBlock->blockStorage())
1158 {
1159 case EbsUnspecified:
1160 case EbsShared:
1161 // Default block storage is shared.
1162 out << "shared";
1163 break;
1164
1165 case EbsPacked:
1166 out << "packed";
1167 break;
1168
1169 case EbsStd140:
1170 out << "std140";
1171 break;
1172
1173 case EbsStd430:
1174 out << "std430";
1175 break;
1176
1177 default:
1178 UNREACHABLE();
1179 break;
1180 }
1181
1182 if (interfaceBlock->blockBinding() >= 0)
1183 {
1184 out << ", ";
1185 out << "binding = " << interfaceBlock->blockBinding();
1186 }
1187
1188 out << ") ";
1189 }
1190
getVariableInterpolation(TQualifier qualifier)1191 const char *getVariableInterpolation(TQualifier qualifier)
1192 {
1193 switch (qualifier)
1194 {
1195 case EvqSmoothOut:
1196 return "smooth out ";
1197 case EvqFlatOut:
1198 return "flat out ";
1199 case EvqNoPerspectiveOut:
1200 return "noperspective out ";
1201 case EvqCentroidOut:
1202 return "centroid out ";
1203 case EvqSmoothIn:
1204 return "smooth in ";
1205 case EvqFlatIn:
1206 return "flat in ";
1207 case EvqNoPerspectiveIn:
1208 return "noperspective in ";
1209 case EvqCentroidIn:
1210 return "centroid in ";
1211 default:
1212 break;
1213 }
1214 return nullptr;
1215 }
1216
declareInterfaceBlock(const TType & type)1217 void TOutputGLSLBase::declareInterfaceBlock(const TType &type)
1218 {
1219 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1220 TInfoSinkBase &out = objSink();
1221
1222 out << hashName(interfaceBlock) << "{\n";
1223 const TFieldList &fields = interfaceBlock->fields();
1224 for (const TField *field : fields)
1225 {
1226 if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
1227 type.getQualifier() != EvqPatchOut)
1228 {
1229 writeFieldLayoutQualifier(field);
1230 }
1231
1232 const TType &fieldType = *field->type();
1233
1234 out << getMemoryQualifiers(fieldType);
1235 if (writeVariablePrecision(fieldType.getPrecision()))
1236 out << " ";
1237 if (fieldType.isInvariant())
1238 {
1239 writeInvariantQualifier(fieldType);
1240 }
1241
1242 const char *qualifier = getVariableInterpolation(fieldType.getQualifier());
1243 if (qualifier != nullptr)
1244 out << qualifier;
1245
1246 out << getTypeName(fieldType) << " " << hashFieldName(field);
1247
1248 if (fieldType.isArray())
1249 out << ArrayString(fieldType);
1250 out << ";\n";
1251 }
1252 out << "}";
1253 }
1254
WritePragma(TInfoSinkBase & out,ShCompileOptions compileOptions,const TPragma & pragma)1255 void WritePragma(TInfoSinkBase &out, ShCompileOptions compileOptions, const TPragma &pragma)
1256 {
1257 if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) == 0)
1258 {
1259 if (pragma.stdgl.invariantAll)
1260 out << "#pragma STDGL invariant(all)\n";
1261 }
1262 }
1263
WriteGeometryShaderLayoutQualifiers(TInfoSinkBase & out,sh::TLayoutPrimitiveType inputPrimitive,int invocations,sh::TLayoutPrimitiveType outputPrimitive,int maxVertices)1264 void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1265 sh::TLayoutPrimitiveType inputPrimitive,
1266 int invocations,
1267 sh::TLayoutPrimitiveType outputPrimitive,
1268 int maxVertices)
1269 {
1270 // Omit 'invocations = 1'
1271 if (inputPrimitive != EptUndefined || invocations > 1)
1272 {
1273 out << "layout (";
1274
1275 if (inputPrimitive != EptUndefined)
1276 {
1277 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1278 }
1279
1280 if (invocations > 1)
1281 {
1282 if (inputPrimitive != EptUndefined)
1283 {
1284 out << ", ";
1285 }
1286 out << "invocations = " << invocations;
1287 }
1288 out << ") in;\n";
1289 }
1290
1291 if (outputPrimitive != EptUndefined || maxVertices != -1)
1292 {
1293 out << "layout (";
1294
1295 if (outputPrimitive != EptUndefined)
1296 {
1297 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1298 }
1299
1300 if (maxVertices != -1)
1301 {
1302 if (outputPrimitive != EptUndefined)
1303 {
1304 out << ", ";
1305 }
1306 out << "max_vertices = " << maxVertices;
1307 }
1308 out << ") out;\n";
1309 }
1310 }
1311
WriteTessControlShaderLayoutQualifiers(TInfoSinkBase & out,int inputVertices)1312 void WriteTessControlShaderLayoutQualifiers(TInfoSinkBase &out, int inputVertices)
1313 {
1314 if (inputVertices != 0)
1315 {
1316 out << "layout (vertices = " << inputVertices << ") out;\n";
1317 }
1318 }
1319
WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase & out,sh::TLayoutTessEvaluationType inputPrimitive,sh::TLayoutTessEvaluationType inputVertexSpacing,sh::TLayoutTessEvaluationType inputOrdering,sh::TLayoutTessEvaluationType inputPoint)1320 void WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase &out,
1321 sh::TLayoutTessEvaluationType inputPrimitive,
1322 sh::TLayoutTessEvaluationType inputVertexSpacing,
1323 sh::TLayoutTessEvaluationType inputOrdering,
1324 sh::TLayoutTessEvaluationType inputPoint)
1325 {
1326 if (inputPrimitive != EtetUndefined)
1327 {
1328 out << "layout (";
1329 out << getTessEvaluationShaderTypeString(inputPrimitive);
1330 if (inputVertexSpacing != EtetUndefined)
1331 {
1332 out << ", " << getTessEvaluationShaderTypeString(inputVertexSpacing);
1333 }
1334 if (inputOrdering != EtetUndefined)
1335 {
1336 out << ", " << getTessEvaluationShaderTypeString(inputOrdering);
1337 }
1338 if (inputPoint != EtetUndefined)
1339 {
1340 out << ", " << getTessEvaluationShaderTypeString(inputPoint);
1341 }
1342 out << ") in;\n";
1343 }
1344 }
1345
1346 // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1347 // variables with specified layout qualifiers are copied. Additional checks are needed against the
1348 // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1349 // TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1350 // NeedsToWriteLayoutQualifier.
NeedsToWriteLayoutQualifier(const TType & type)1351 bool NeedsToWriteLayoutQualifier(const TType &type)
1352 {
1353 if (type.getBasicType() == EbtInterfaceBlock)
1354 {
1355 return true;
1356 }
1357
1358 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1359
1360 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1361 IsVarying(type.getQualifier())) &&
1362 layoutQualifier.location >= 0)
1363 {
1364 return true;
1365 }
1366
1367 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1368 {
1369 return true;
1370 }
1371
1372 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1373 {
1374 return true;
1375 }
1376
1377 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1378 {
1379 return true;
1380 }
1381 return false;
1382 }
1383
EmitEarlyFragmentTestsGLSL(const TCompiler & compiler,TInfoSinkBase & sink)1384 void EmitEarlyFragmentTestsGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
1385 {
1386 if (compiler.isEarlyFragmentTestsSpecified() || compiler.isEarlyFragmentTestsOptimized())
1387 {
1388 sink << "layout (early_fragment_tests) in;\n";
1389 }
1390 }
1391
EmitWorkGroupSizeGLSL(const TCompiler & compiler,TInfoSinkBase & sink)1392 void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
1393 {
1394 if (compiler.isComputeShaderLocalSizeDeclared())
1395 {
1396 const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize();
1397 sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
1398 << ", local_size_z=" << localSize[2] << ") in;\n";
1399 }
1400 }
1401
EmitMultiviewGLSL(const TCompiler & compiler,const ShCompileOptions & compileOptions,const TExtension extension,const TBehavior behavior,TInfoSinkBase & sink)1402 void EmitMultiviewGLSL(const TCompiler &compiler,
1403 const ShCompileOptions &compileOptions,
1404 const TExtension extension,
1405 const TBehavior behavior,
1406 TInfoSinkBase &sink)
1407 {
1408 ASSERT(behavior != EBhUndefined);
1409 if (behavior == EBhDisable)
1410 return;
1411
1412 const bool isVertexShader = (compiler.getShaderType() == GL_VERTEX_SHADER);
1413 if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) != 0)
1414 {
1415 // Emit ARB_shader_viewport_layer_array/NV_viewport_array2 in a vertex shader if the
1416 // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
1417 // OVR_multiview(2) extension is requested.
1418 if (isVertexShader && (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0)
1419 {
1420 sink << "#if defined(GL_ARB_shader_viewport_layer_array)\n"
1421 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
1422 << "#elif defined(GL_NV_viewport_array2)\n"
1423 << "#extension GL_NV_viewport_array2 : require\n"
1424 << "#endif\n";
1425 }
1426 }
1427 else
1428 {
1429 sink << "#extension GL_OVR_multiview";
1430 if (extension == TExtension::OVR_multiview2)
1431 {
1432 sink << "2";
1433 }
1434 sink << " : " << GetBehaviorString(behavior) << "\n";
1435
1436 const auto &numViews = compiler.getNumViews();
1437 if (isVertexShader && numViews != -1)
1438 {
1439 sink << "layout(num_views=" << numViews << ") in;\n";
1440 }
1441 }
1442 }
1443
1444 } // namespace sh
1445