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 TIntermSymbol *symbolNode = variable->getAsSymbolNode();
1094 if (!symbolNode || symbolNode->getName() != "gl_ClipDistance")
1095 {
1096 // gl_ClipDistance re-declaration doesn't need layout.
1097 writeLayoutQualifier(variable);
1098 }
1099 writeVariableType(variable->getType(), symbolNode ? &symbolNode->variable() : nullptr,
1100 false);
1101 if (variable->getAsSymbolNode() == nullptr ||
1102 variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty)
1103 {
1104 out << " ";
1105 }
1106 mDeclaringVariable = true;
1107 }
1108 else if (visit == InVisit)
1109 {
1110 UNREACHABLE();
1111 }
1112 else
1113 {
1114 mDeclaringVariable = false;
1115 }
1116 return true;
1117 }
1118
visitLoop(Visit visit,TIntermLoop * node)1119 bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
1120 {
1121 TInfoSinkBase &out = objSink();
1122
1123 TLoopType loopType = node->getType();
1124
1125 if (loopType == ELoopFor) // for loop
1126 {
1127 out << "for (";
1128 if (node->getInit())
1129 node->getInit()->traverse(this);
1130 out << "; ";
1131
1132 if (node->getCondition())
1133 node->getCondition()->traverse(this);
1134 out << "; ";
1135
1136 if (node->getExpression())
1137 node->getExpression()->traverse(this);
1138 out << ")\n";
1139
1140 visitCodeBlock(node->getBody());
1141 }
1142 else if (loopType == ELoopWhile) // while loop
1143 {
1144 out << "while (";
1145 ASSERT(node->getCondition() != nullptr);
1146 node->getCondition()->traverse(this);
1147 out << ")\n";
1148
1149 visitCodeBlock(node->getBody());
1150 }
1151 else // do-while loop
1152 {
1153 ASSERT(loopType == ELoopDoWhile);
1154 out << "do\n";
1155
1156 visitCodeBlock(node->getBody());
1157
1158 out << "while (";
1159 ASSERT(node->getCondition() != nullptr);
1160 node->getCondition()->traverse(this);
1161 out << ");\n";
1162 }
1163
1164 // No need to visit children. They have been already processed in
1165 // this function.
1166 return false;
1167 }
1168
visitBranch(Visit visit,TIntermBranch * node)1169 bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1170 {
1171 switch (node->getFlowOp())
1172 {
1173 case EOpKill:
1174 writeTriplet(visit, "discard", nullptr, nullptr);
1175 break;
1176 case EOpBreak:
1177 writeTriplet(visit, "break", nullptr, nullptr);
1178 break;
1179 case EOpContinue:
1180 writeTriplet(visit, "continue", nullptr, nullptr);
1181 break;
1182 case EOpReturn:
1183 writeTriplet(visit, "return ", nullptr, nullptr);
1184 break;
1185 default:
1186 UNREACHABLE();
1187 }
1188
1189 return true;
1190 }
1191
visitCodeBlock(TIntermBlock * node)1192 void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1193 {
1194 TInfoSinkBase &out = objSink();
1195 if (node != nullptr)
1196 {
1197 node->traverse(this);
1198 // Single statements not part of a sequence need to be terminated
1199 // with semi-colon.
1200 if (isSingleStatement(node))
1201 out << ";\n";
1202 }
1203 else
1204 {
1205 out << "{\n}\n"; // Empty code block.
1206 }
1207 }
1208
visitPreprocessorDirective(TIntermPreprocessorDirective * node)1209 void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1210 {
1211 TInfoSinkBase &out = objSink();
1212
1213 out << "\n";
1214
1215 switch (node->getDirective())
1216 {
1217 case PreprocessorDirective::Define:
1218 out << "#define";
1219 break;
1220 case PreprocessorDirective::Endif:
1221 out << "#endif";
1222 break;
1223 case PreprocessorDirective::If:
1224 out << "#if";
1225 break;
1226 case PreprocessorDirective::Ifdef:
1227 out << "#ifdef";
1228 break;
1229
1230 default:
1231 UNREACHABLE();
1232 break;
1233 }
1234
1235 if (!node->getCommand().empty())
1236 {
1237 out << " " << node->getCommand();
1238 }
1239
1240 out << "\n";
1241 }
1242
getTypeName(const TType & type)1243 ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
1244 {
1245 if (type.getBasicType() == EbtSamplerVideoWEBGL)
1246 {
1247 // TODO(http://anglebug.com/3889): translate SamplerVideoWEBGL into different token
1248 // when necessary (e.g. on Android devices)
1249 return ImmutableString("sampler2D");
1250 }
1251
1252 return GetTypeName(type, mHashFunction, &mNameMap);
1253 }
1254
hashName(const TSymbol * symbol)1255 ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
1256 {
1257 return HashName(symbol, mHashFunction, &mNameMap);
1258 }
1259
hashFieldName(const TField * field)1260 ImmutableString TOutputGLSLBase::hashFieldName(const TField *field)
1261 {
1262 ASSERT(field->symbolType() != SymbolType::Empty);
1263 if (field->symbolType() == SymbolType::UserDefined)
1264 {
1265 return HashName(field->name(), mHashFunction, &mNameMap);
1266 }
1267
1268 return field->name();
1269 }
1270
hashFunctionNameIfNeeded(const TFunction * func)1271 ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
1272 {
1273 if (func->isMain())
1274 {
1275 return func->name();
1276 }
1277 else
1278 {
1279 return hashName(func);
1280 }
1281 }
1282
structDeclared(const TStructure * structure) const1283 bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
1284 {
1285 ASSERT(structure);
1286 if (structure->symbolType() == SymbolType::Empty)
1287 {
1288 return false;
1289 }
1290
1291 return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
1292 }
1293
declareStruct(const TStructure * structure)1294 void TOutputGLSLBase::declareStruct(const TStructure *structure)
1295 {
1296 TInfoSinkBase &out = objSink();
1297
1298 out << "struct ";
1299
1300 if (structure->symbolType() != SymbolType::Empty)
1301 {
1302 out << hashName(structure) << " ";
1303 }
1304 out << "{\n";
1305 const TFieldList &fields = structure->fields();
1306 for (size_t i = 0; i < fields.size(); ++i)
1307 {
1308 const TField *field = fields[i];
1309 if (writeVariablePrecision(field->type()->getPrecision()))
1310 out << " ";
1311 out << getTypeName(*field->type()) << " " << hashFieldName(field);
1312 if (field->type()->isArray())
1313 out << ArrayString(*field->type());
1314 out << ";\n";
1315 }
1316 out << "}";
1317
1318 if (structure->symbolType() != SymbolType::Empty)
1319 {
1320 mDeclaredStructs.insert(structure->uniqueId().get());
1321 }
1322 }
1323
declareInterfaceBlockLayout(const TInterfaceBlock * interfaceBlock)1324 void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1325 {
1326 TInfoSinkBase &out = objSink();
1327
1328 out << "layout(";
1329
1330 switch (interfaceBlock->blockStorage())
1331 {
1332 case EbsUnspecified:
1333 case EbsShared:
1334 // Default block storage is shared.
1335 out << "shared";
1336 break;
1337
1338 case EbsPacked:
1339 out << "packed";
1340 break;
1341
1342 case EbsStd140:
1343 out << "std140";
1344 break;
1345
1346 case EbsStd430:
1347 out << "std430";
1348 break;
1349
1350 default:
1351 UNREACHABLE();
1352 break;
1353 }
1354
1355 if (interfaceBlock->blockBinding() >= 0)
1356 {
1357 out << ", ";
1358 out << "binding = " << interfaceBlock->blockBinding();
1359 }
1360
1361 out << ") ";
1362 }
1363
declareInterfaceBlock(const TInterfaceBlock * interfaceBlock)1364 void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1365 {
1366 TInfoSinkBase &out = objSink();
1367
1368 out << hashName(interfaceBlock) << "{\n";
1369 const TFieldList &fields = interfaceBlock->fields();
1370 for (const TField *field : fields)
1371 {
1372 writeFieldLayoutQualifier(field);
1373 out << getMemoryQualifiers(*field->type());
1374
1375 if (writeVariablePrecision(field->type()->getPrecision()))
1376 out << " ";
1377 out << getTypeName(*field->type()) << " " << hashFieldName(field);
1378 if (field->type()->isArray())
1379 out << ArrayString(*field->type());
1380 out << ";\n";
1381 }
1382 out << "}";
1383 }
1384
WriteGeometryShaderLayoutQualifiers(TInfoSinkBase & out,sh::TLayoutPrimitiveType inputPrimitive,int invocations,sh::TLayoutPrimitiveType outputPrimitive,int maxVertices)1385 void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1386 sh::TLayoutPrimitiveType inputPrimitive,
1387 int invocations,
1388 sh::TLayoutPrimitiveType outputPrimitive,
1389 int maxVertices)
1390 {
1391 // Omit 'invocations = 1'
1392 if (inputPrimitive != EptUndefined || invocations > 1)
1393 {
1394 out << "layout (";
1395
1396 if (inputPrimitive != EptUndefined)
1397 {
1398 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1399 }
1400
1401 if (invocations > 1)
1402 {
1403 if (inputPrimitive != EptUndefined)
1404 {
1405 out << ", ";
1406 }
1407 out << "invocations = " << invocations;
1408 }
1409 out << ") in;\n";
1410 }
1411
1412 if (outputPrimitive != EptUndefined || maxVertices != -1)
1413 {
1414 out << "layout (";
1415
1416 if (outputPrimitive != EptUndefined)
1417 {
1418 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1419 }
1420
1421 if (maxVertices != -1)
1422 {
1423 if (outputPrimitive != EptUndefined)
1424 {
1425 out << ", ";
1426 }
1427 out << "max_vertices = " << maxVertices;
1428 }
1429 out << ") out;\n";
1430 }
1431 }
1432
1433 // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1434 // variables with specified layout qualifiers are copied. Additional checks are needed against the
1435 // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1436 // TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1437 // NeedsToWriteLayoutQualifier.
NeedsToWriteLayoutQualifier(const TType & type)1438 bool NeedsToWriteLayoutQualifier(const TType &type)
1439 {
1440 if (type.getBasicType() == EbtInterfaceBlock)
1441 {
1442 return true;
1443 }
1444
1445 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1446
1447 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1448 IsVarying(type.getQualifier())) &&
1449 layoutQualifier.location >= 0)
1450 {
1451 return true;
1452 }
1453
1454 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1455 {
1456 return true;
1457 }
1458
1459 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1460 {
1461 return true;
1462 }
1463
1464 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1465 {
1466 return true;
1467 }
1468 return false;
1469 }
1470
1471 } // namespace sh
1472