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