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