Home | History | Annotate | Download | only in sksl
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkSLGLSLCodeGenerator.h"
      9 
     10 #include "SkSLCompiler.h"
     11 #include "ir/SkSLExpressionStatement.h"
     12 #include "ir/SkSLExtension.h"
     13 #include "ir/SkSLIndexExpression.h"
     14 #include "ir/SkSLModifiersDeclaration.h"
     15 #include "ir/SkSLNop.h"
     16 #include "ir/SkSLVariableReference.h"
     17 
     18 #ifndef SKSL_STANDALONE
     19 #include "SkOnce.h"
     20 #endif
     21 
     22 namespace SkSL {
     23 
     24 void GLSLCodeGenerator::write(const char* s) {
     25     if (s[0] == 0) {
     26         return;
     27     }
     28     if (fAtLineStart) {
     29         for (int i = 0; i < fIndentation; i++) {
     30             fOut->writeText("    ");
     31         }
     32     }
     33     fOut->writeText(s);
     34     fAtLineStart = false;
     35 }
     36 
     37 void GLSLCodeGenerator::writeLine(const char* s) {
     38     this->write(s);
     39     fOut->writeText(fLineEnding);
     40     fAtLineStart = true;
     41 }
     42 
     43 void GLSLCodeGenerator::write(const String& s) {
     44     this->write(s.c_str());
     45 }
     46 
     47 void GLSLCodeGenerator::write(StringFragment s) {
     48     if (!s.fLength) {
     49         return;
     50     }
     51     if (fAtLineStart) {
     52         for (int i = 0; i < fIndentation; i++) {
     53             fOut->writeText("    ");
     54         }
     55     }
     56     fOut->write(s.fChars, s.fLength);
     57     fAtLineStart = false;
     58 }
     59 
     60 void GLSLCodeGenerator::writeLine(const String& s) {
     61     this->writeLine(s.c_str());
     62 }
     63 
     64 void GLSLCodeGenerator::writeLine() {
     65     this->writeLine("");
     66 }
     67 
     68 void GLSLCodeGenerator::writeExtension(const String& name) {
     69     this->writeExtension(name, true);
     70 }
     71 
     72 void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
     73     fExtensions.writeText("#extension ");
     74     fExtensions.write(name.c_str(), name.length());
     75     fExtensions.writeText(require ? " : require\n" : " : enable\n");
     76 }
     77 
     78 bool GLSLCodeGenerator::usesPrecisionModifiers() const {
     79     return fProgram.fSettings.fCaps->usesPrecisionModifiers();
     80 }
     81 
     82 String GLSLCodeGenerator::getTypeName(const Type& type) {
     83     switch (type.kind()) {
     84         case Type::kVector_Kind: {
     85             Type component = type.componentType();
     86             String result;
     87             if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
     88                 result = "vec";
     89             }
     90             else if (component == *fContext.fDouble_Type) {
     91                 result = "dvec";
     92             }
     93             else if (component.isSigned()) {
     94                 result = "ivec";
     95             }
     96             else if (component.isUnsigned()) {
     97                 result = "uvec";
     98             }
     99             else if (component == *fContext.fBool_Type) {
    100                 result = "bvec";
    101             }
    102             else {
    103                 ABORT("unsupported vector type");
    104             }
    105             result += to_string(type.columns());
    106             return result;
    107         }
    108         case Type::kMatrix_Kind: {
    109             String result;
    110             Type component = type.componentType();
    111             if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
    112                 result = "mat";
    113             }
    114             else if (component == *fContext.fDouble_Type) {
    115                 result = "dmat";
    116             }
    117             else {
    118                 ABORT("unsupported matrix type");
    119             }
    120             result += to_string(type.columns());
    121             if (type.columns() != type.rows()) {
    122                 result += "x";
    123                 result += to_string(type.rows());
    124             }
    125             return result;
    126         }
    127         case Type::kArray_Kind: {
    128             String result = this->getTypeName(type.componentType()) + "[";
    129             if (type.columns() != -1) {
    130                 result += to_string(type.columns());
    131             }
    132             result += "]";
    133             return result;
    134         }
    135         case Type::kScalar_Kind: {
    136             if (type == *fContext.fHalf_Type) {
    137                 return "float";
    138             }
    139             else if (type == *fContext.fShort_Type) {
    140                 return "int";
    141             }
    142             else if (type == *fContext.fUShort_Type) {
    143                 return "uint";
    144             }
    145             else if (type == *fContext.fByte_Type) {
    146                 return "int";
    147             }
    148             else if (type == *fContext.fUByte_Type) {
    149                 return "uint";
    150             }
    151             else {
    152                 return type.name();
    153             }
    154             break;
    155         }
    156         default:
    157             return type.name();
    158     }
    159 }
    160 
    161 void GLSLCodeGenerator::writeType(const Type& type) {
    162     if (type.kind() == Type::kStruct_Kind) {
    163         for (const Type* search : fWrittenStructs) {
    164             if (*search == type) {
    165                 // already written
    166                 this->write(type.fName);
    167                 return;
    168             }
    169         }
    170         fWrittenStructs.push_back(&type);
    171         this->write("struct ");
    172         this->write(type.fName);
    173         this->writeLine(" {");
    174         fIndentation++;
    175         for (const auto& f : type.fields()) {
    176             this->writeModifiers(f.fModifiers, false);
    177             this->writeTypePrecision(*f.fType);
    178             // sizes (which must be static in structs) are part of the type name here
    179             this->writeType(*f.fType);
    180             this->write(" ");
    181             this->write(f.fName);
    182             this->writeLine(";");
    183         }
    184         fIndentation--;
    185         this->write("}");
    186     } else {
    187         this->write(this->getTypeName(type));
    188     }
    189 }
    190 
    191 void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
    192     switch (expr.fKind) {
    193         case Expression::kBinary_Kind:
    194             this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
    195             break;
    196         case Expression::kBoolLiteral_Kind:
    197             this->writeBoolLiteral((BoolLiteral&) expr);
    198             break;
    199         case Expression::kConstructor_Kind:
    200             this->writeConstructor((Constructor&) expr, parentPrecedence);
    201             break;
    202         case Expression::kIntLiteral_Kind:
    203             this->writeIntLiteral((IntLiteral&) expr);
    204             break;
    205         case Expression::kFieldAccess_Kind:
    206             this->writeFieldAccess(((FieldAccess&) expr));
    207             break;
    208         case Expression::kFloatLiteral_Kind:
    209             this->writeFloatLiteral(((FloatLiteral&) expr));
    210             break;
    211         case Expression::kFunctionCall_Kind:
    212             this->writeFunctionCall((FunctionCall&) expr);
    213             break;
    214         case Expression::kPrefix_Kind:
    215             this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
    216             break;
    217         case Expression::kPostfix_Kind:
    218             this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
    219             break;
    220         case Expression::kSetting_Kind:
    221             this->writeSetting((Setting&) expr);
    222             break;
    223         case Expression::kSwizzle_Kind:
    224             this->writeSwizzle((Swizzle&) expr);
    225             break;
    226         case Expression::kVariableReference_Kind:
    227             this->writeVariableReference((VariableReference&) expr);
    228             break;
    229         case Expression::kTernary_Kind:
    230             this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
    231             break;
    232         case Expression::kIndex_Kind:
    233             this->writeIndexExpression((IndexExpression&) expr);
    234             break;
    235         default:
    236             ABORT("unsupported expression: %s", expr.description().c_str());
    237     }
    238 }
    239 
    240 static bool is_abs(Expression& expr) {
    241     if (expr.fKind != Expression::kFunctionCall_Kind) {
    242         return false;
    243     }
    244     return ((FunctionCall&) expr).fFunction.fName == "abs";
    245 }
    246 
    247 // turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
    248 // Tegra3 compiler bug.
    249 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
    250     SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
    251     String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
    252     String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
    253     this->fFunctionHeader += String("    ") + this->getTypePrecision(absExpr.fType) +
    254                              this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
    255     this->fFunctionHeader += String("    ") + this->getTypePrecision(otherExpr.fType) +
    256                              this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
    257     this->write("((" + tmpVar1 + " = ");
    258     this->writeExpression(absExpr, kTopLevel_Precedence);
    259     this->write(") < (" + tmpVar2 + " = ");
    260     this->writeExpression(otherExpr, kAssignment_Precedence);
    261     this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
    262 }
    263 
    264 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
    265     this->write("(1.0 / sqrt(");
    266     this->writeExpression(x, kTopLevel_Precedence);
    267     this->write("))");
    268 }
    269 
    270 void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
    271     String name;
    272     if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
    273         name = "_determinant2";
    274         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    275             fWrittenIntrinsics.insert(name);
    276             fExtraFunctions.writeText((
    277                 "float " + name + "(mat2 m) {"
    278                 "    return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
    279                 "}"
    280             ).c_str());
    281         }
    282     }
    283     else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
    284         name = "_determinant3";
    285         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    286             fWrittenIntrinsics.insert(name);
    287             fExtraFunctions.writeText((
    288                 "float " + name + "(mat3 m) {"
    289                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
    290                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
    291                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
    292                 "    float b01 = a22 * a11 - a12 * a21;"
    293                 "    float b11 = -a22 * a10 + a12 * a20;"
    294                 "    float b21 = a21 * a10 - a11 * a20;"
    295                 "    return a00 * b01 + a01 * b11 + a02 * b21;"
    296                 "}"
    297             ).c_str());
    298         }
    299     }
    300     else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
    301         name = "_determinant3";
    302         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    303             fWrittenIntrinsics.insert(name);
    304             fExtraFunctions.writeText((
    305                 "mat4 " + name + "(mat4 m) {"
    306                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
    307                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
    308                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
    309                 "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
    310                 "    float b00 = a00 * a11 - a01 * a10;"
    311                 "    float b01 = a00 * a12 - a02 * a10;"
    312                 "    float b02 = a00 * a13 - a03 * a10;"
    313                 "    float b03 = a01 * a12 - a02 * a11;"
    314                 "    float b04 = a01 * a13 - a03 * a11;"
    315                 "    float b05 = a02 * a13 - a03 * a12;"
    316                 "    float b06 = a20 * a31 - a21 * a30;"
    317                 "    float b07 = a20 * a32 - a22 * a30;"
    318                 "    float b08 = a20 * a33 - a23 * a30;"
    319                 "    float b09 = a21 * a32 - a22 * a31;"
    320                 "    float b10 = a21 * a33 - a23 * a31;"
    321                 "    float b11 = a22 * a33 - a23 * a32;"
    322                 "    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
    323                 "}"
    324             ).c_str());
    325         }
    326     }
    327     else {
    328         SkASSERT(false);
    329     }
    330     this->write(name + "(");
    331     this->writeExpression(mat, kTopLevel_Precedence);
    332     this->write(")");
    333 }
    334 
    335 void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
    336     String name;
    337     if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
    338         name = "_inverse2";
    339         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    340             fWrittenIntrinsics.insert(name);
    341             fExtraFunctions.writeText((
    342                 "mat2 " + name + "(mat2 m) {"
    343                 "    return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
    344                                "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
    345                 "}"
    346             ).c_str());
    347         }
    348     }
    349     else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
    350         name = "_inverse3";
    351         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    352             fWrittenIntrinsics.insert(name);
    353             fExtraFunctions.writeText((
    354                 "mat3 " +  name + "(mat3 m) {"
    355                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
    356                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
    357                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
    358                 "    float b01 = a22 * a11 - a12 * a21;"
    359                 "    float b11 = -a22 * a10 + a12 * a20;"
    360                 "    float b21 = a21 * a10 - a11 * a20;"
    361                 "    float det = a00 * b01 + a01 * b11 + a02 * b21;"
    362                 "    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
    363                 "                b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
    364                 "                b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
    365                 "}"
    366             ).c_str());
    367         }
    368     }
    369     else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
    370         name = "_inverse4";
    371         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    372             fWrittenIntrinsics.insert(name);
    373             fExtraFunctions.writeText((
    374                 "mat4 " + name + "(mat4 m) {"
    375                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
    376                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
    377                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
    378                 "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
    379                 "    float b00 = a00 * a11 - a01 * a10;"
    380                 "    float b01 = a00 * a12 - a02 * a10;"
    381                 "    float b02 = a00 * a13 - a03 * a10;"
    382                 "    float b03 = a01 * a12 - a02 * a11;"
    383                 "    float b04 = a01 * a13 - a03 * a11;"
    384                 "    float b05 = a02 * a13 - a03 * a12;"
    385                 "    float b06 = a20 * a31 - a21 * a30;"
    386                 "    float b07 = a20 * a32 - a22 * a30;"
    387                 "    float b08 = a20 * a33 - a23 * a30;"
    388                 "    float b09 = a21 * a32 - a22 * a31;"
    389                 "    float b10 = a21 * a33 - a23 * a31;"
    390                 "    float b11 = a22 * a33 - a23 * a32;"
    391                 "    float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
    392                 "                b04 * b07 + b05 * b06;"
    393                 "    return mat4("
    394                 "        a11 * b11 - a12 * b10 + a13 * b09,"
    395                 "        a02 * b10 - a01 * b11 - a03 * b09,"
    396                 "        a31 * b05 - a32 * b04 + a33 * b03,"
    397                 "        a22 * b04 - a21 * b05 - a23 * b03,"
    398                 "        a12 * b08 - a10 * b11 - a13 * b07,"
    399                 "        a00 * b11 - a02 * b08 + a03 * b07,"
    400                 "        a32 * b02 - a30 * b05 - a33 * b01,"
    401                 "        a20 * b05 - a22 * b02 + a23 * b01,"
    402                 "        a10 * b10 - a11 * b08 + a13 * b06,"
    403                 "        a01 * b08 - a00 * b10 - a03 * b06,"
    404                 "        a30 * b04 - a31 * b02 + a33 * b00,"
    405                 "        a21 * b02 - a20 * b04 - a23 * b00,"
    406                 "        a11 * b07 - a10 * b09 - a12 * b06,"
    407                 "        a00 * b09 - a01 * b07 + a02 * b06,"
    408                 "        a31 * b01 - a30 * b03 - a32 * b00,"
    409                 "        a20 * b03 - a21 * b01 + a22 * b00) / det;"
    410                 "}"
    411             ).c_str());
    412         }
    413     }
    414     else {
    415         SkASSERT(false);
    416     }
    417     this->write(name + "(");
    418     this->writeExpression(mat, kTopLevel_Precedence);
    419     this->write(")");
    420 }
    421 
    422 void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
    423     String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
    424     if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    425         fWrittenIntrinsics.insert(name);
    426         String type = this->getTypeName(mat.fType);
    427         const Type& base = mat.fType.componentType();
    428         String transposed =  this->getTypeName(base.toCompound(fContext,
    429                                                                mat.fType.rows(),
    430                                                                mat.fType.columns()));
    431         fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
    432                                   transposed + "(").c_str());
    433         const char* separator = "";
    434         for (int row = 0; row < mat.fType.rows(); ++row) {
    435             for (int column = 0; column < mat.fType.columns(); ++column) {
    436                 fExtraFunctions.writeText(separator);
    437                 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
    438                                            "]").c_str());
    439                 separator = ", ";
    440             }
    441         }
    442         fExtraFunctions.writeText("); }");
    443     }
    444     this->write(name + "(");
    445     this->writeExpression(mat, kTopLevel_Precedence);
    446     this->write(")");
    447 }
    448 
    449 std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
    450                                                       GLSLCodeGenerator::fFunctionClasses = nullptr;
    451 
    452 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
    453 #ifdef SKSL_STANDALONE
    454     if (!fFunctionClasses) {
    455 #else
    456     static SkOnce once;
    457     once([] {
    458 #endif
    459         fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
    460         (*fFunctionClasses)["abs"]         = FunctionClass::kAbs;
    461         (*fFunctionClasses)["atan"]        = FunctionClass::kAtan;
    462         (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
    463         (*fFunctionClasses)["dFdx"]        = FunctionClass::kDFdx;
    464         (*fFunctionClasses)["dFdy"]        = FunctionClass::kDFdy;
    465         (*fFunctionClasses)["fwidth"]      = FunctionClass::kFwidth;
    466         (*fFunctionClasses)["fma"]         = FunctionClass::kFMA;
    467         (*fFunctionClasses)["fract"]       = FunctionClass::kFract;
    468         (*fFunctionClasses)["inverse"]     = FunctionClass::kInverse;
    469         (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
    470         (*fFunctionClasses)["min"]         = FunctionClass::kMin;
    471         (*fFunctionClasses)["pow"]         = FunctionClass::kPow;
    472         (*fFunctionClasses)["saturate"]    = FunctionClass::kSaturate;
    473         (*fFunctionClasses)["texture"]     = FunctionClass::kTexture;
    474         (*fFunctionClasses)["transpose"]   = FunctionClass::kTranspose;
    475     }
    476 #ifndef SKSL_STANDALONE
    477     );
    478 #endif
    479     const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
    480                                               fFunctionClasses->end();
    481     bool isTextureFunctionWithBias = false;
    482     bool nameWritten = false;
    483     if (found != fFunctionClasses->end()) {
    484         switch (found->second) {
    485             case FunctionClass::kAbs: {
    486                 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
    487                     break;
    488                 SkASSERT(c.fArguments.size() == 1);
    489                 if (c.fArguments[0]->fType != *fContext.fInt_Type)
    490                   break;
    491                 // abs(int) on Intel OSX is incorrect, so emulate it:
    492                 String name = "_absemulation";
    493                 this->write(name);
    494                 nameWritten = true;
    495                 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
    496                     fWrittenIntrinsics.insert(name);
    497                     fExtraFunctions.writeText((
    498                         "int " + name + "(int x) {\n"
    499                         "    return x * sign(x);\n"
    500                         "}\n"
    501                     ).c_str());
    502                 }
    503                 break;
    504             }
    505             case FunctionClass::kAtan:
    506                 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
    507                     c.fArguments.size() == 2 &&
    508                     c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
    509                     const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
    510                     if (p.fOperator == Token::MINUS) {
    511                         this->write("atan(");
    512                         this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    513                         this->write(", -1.0 * ");
    514                         this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
    515                         this->write(")");
    516                         return;
    517                     }
    518                 }
    519                 break;
    520             case FunctionClass::kDFdy:
    521                 if (fProgram.fSettings.fFlipY) {
    522                     // Flipping Y also negates the Y derivatives.
    523                     this->write("-dFdy");
    524                     nameWritten = true;
    525                 }
    526                 // fallthru
    527             case FunctionClass::kDFdx:
    528             case FunctionClass::kFwidth:
    529                 if (!fFoundDerivatives &&
    530                     fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
    531                     SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
    532                     this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
    533                     fFoundDerivatives = true;
    534                 }
    535                 break;
    536             case FunctionClass::kDeterminant:
    537                 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
    538                     SkASSERT(c.fArguments.size() == 1);
    539                     this->writeDeterminantHack(*c.fArguments[0]);
    540                     return;
    541                 }
    542                 break;
    543             case FunctionClass::kFMA:
    544                 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
    545                     SkASSERT(c.fArguments.size() == 3);
    546                     this->write("((");
    547                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    548                     this->write(") * (");
    549                     this->writeExpression(*c.fArguments[1], kSequence_Precedence);
    550                     this->write(") + (");
    551                     this->writeExpression(*c.fArguments[2], kSequence_Precedence);
    552                     this->write("))");
    553                     return;
    554                 }
    555                 break;
    556             case FunctionClass::kFract:
    557                 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
    558                     SkASSERT(c.fArguments.size() == 1);
    559                     this->write("(0.5 - sign(");
    560                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    561                     this->write(") * (0.5 - fract(abs(");
    562                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    563                     this->write("))))");
    564                     return;
    565                 }
    566                 break;
    567             case FunctionClass::kInverse:
    568                 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
    569                     SkASSERT(c.fArguments.size() == 1);
    570                     this->writeInverseHack(*c.fArguments[0]);
    571                     return;
    572                 }
    573                 break;
    574             case FunctionClass::kInverseSqrt:
    575                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
    576                     SkASSERT(c.fArguments.size() == 1);
    577                     this->writeInverseSqrtHack(*c.fArguments[0]);
    578                     return;
    579                 }
    580                 break;
    581             case FunctionClass::kMin:
    582                 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
    583                     SkASSERT(c.fArguments.size() == 2);
    584                     if (is_abs(*c.fArguments[0])) {
    585                         this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
    586                         return;
    587                     }
    588                     if (is_abs(*c.fArguments[1])) {
    589                         // note that this violates the GLSL left-to-right evaluation semantics.
    590                         // I doubt it will ever end up mattering, but it's worth calling out.
    591                         this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
    592                         return;
    593                     }
    594                 }
    595                 break;
    596             case FunctionClass::kPow:
    597                 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
    598                     break;
    599                 }
    600                 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
    601                 // constant.  It's hard to tell what constitutes "constant" here
    602                 // so just replace in all cases.
    603 
    604                 // Change pow(x, y) into exp2(y * log2(x))
    605                 this->write("exp2(");
    606                 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
    607                 this->write(" * log2(");
    608                 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    609                 this->write("))");
    610                 return;
    611             case FunctionClass::kSaturate:
    612                 SkASSERT(c.fArguments.size() == 1);
    613                 this->write("clamp(");
    614                 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
    615                 this->write(", 0.0, 1.0)");
    616                 return;
    617             case FunctionClass::kTexture: {
    618                 const char* dim = "";
    619                 bool proj = false;
    620                 switch (c.fArguments[0]->fType.dimensions()) {
    621                     case SpvDim1D:
    622                         dim = "1D";
    623                         isTextureFunctionWithBias = true;
    624                         if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
    625                             proj = false;
    626                         } else {
    627                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
    628                             proj = true;
    629                         }
    630                         break;
    631                     case SpvDim2D:
    632                         dim = "2D";
    633                         if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
    634                             isTextureFunctionWithBias = true;
    635                         }
    636                         if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
    637                             proj = false;
    638                         } else {
    639                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
    640                             proj = true;
    641                         }
    642                         break;
    643                     case SpvDim3D:
    644                         dim = "3D";
    645                         isTextureFunctionWithBias = true;
    646                         if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
    647                             proj = false;
    648                         } else {
    649                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
    650                             proj = true;
    651                         }
    652                         break;
    653                     case SpvDimCube:
    654                         dim = "Cube";
    655                         isTextureFunctionWithBias = true;
    656                         proj = false;
    657                         break;
    658                     case SpvDimRect:
    659                         dim = "Rect";
    660                         proj = false;
    661                         break;
    662                     case SpvDimBuffer:
    663                         SkASSERT(false); // doesn't exist
    664                         dim = "Buffer";
    665                         proj = false;
    666                         break;
    667                     case SpvDimSubpassData:
    668                         SkASSERT(false); // doesn't exist
    669                         dim = "SubpassData";
    670                         proj = false;
    671                         break;
    672                 }
    673                 this->write("texture");
    674                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
    675                     this->write(dim);
    676                 }
    677                 if (proj) {
    678                     this->write("Proj");
    679                 }
    680                 nameWritten = true;
    681                 break;
    682             }
    683             case FunctionClass::kTranspose:
    684                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
    685                     SkASSERT(c.fArguments.size() == 1);
    686                     this->writeTransposeHack(*c.fArguments[0]);
    687                     return;
    688                 }
    689                 break;
    690         }
    691     }
    692     if (!nameWritten) {
    693         this->write(c.fFunction.fName);
    694     }
    695     this->write("(");
    696     const char* separator = "";
    697     for (const auto& arg : c.fArguments) {
    698         this->write(separator);
    699         separator = ", ";
    700         this->writeExpression(*arg, kSequence_Precedence);
    701     }
    702     if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
    703         this->write(", -0.5");
    704     }
    705     this->write(")");
    706 }
    707 
    708 void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
    709     if (c.fArguments.size() == 1 &&
    710         (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
    711         (c.fType.kind() == Type::kScalar_Kind &&
    712          c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
    713         // in cases like half(float), they're different types as far as SkSL is concerned but the
    714         // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
    715         // out the inner expression here.
    716         this->writeExpression(*c.fArguments[0], parentPrecedence);
    717         return;
    718     }
    719     this->writeType(c.fType);
    720     this->write("(");
    721     const char* separator = "";
    722     for (const auto& arg : c.fArguments) {
    723         this->write(separator);
    724         separator = ", ";
    725         this->writeExpression(*arg, kSequence_Precedence);
    726     }
    727     this->write(")");
    728 }
    729 
    730 void GLSLCodeGenerator::writeFragCoord() {
    731     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
    732         if (!fSetupFragCoordWorkaround) {
    733             const char* precision = usesPrecisionModifiers() ? "highp " : "";
    734             fFunctionHeader += precision;
    735             fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
    736             fFunctionHeader += precision;
    737             fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
    738                 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
    739             // Ensure that we get exact .5 values for x and y.
    740             fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
    741                                "vec2(.5);\n";
    742             fSetupFragCoordWorkaround = true;
    743         }
    744         this->write("sk_FragCoord_Resolved");
    745         return;
    746     }
    747 
    748     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
    749     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
    750     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
    751     if (!fProgram.fSettings.fFlipY) {
    752         this->write("gl_FragCoord");
    753     } else if (const char* extension =
    754                                   fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
    755         if (!fSetupFragPositionGlobal) {
    756             if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
    757                 this->writeExtension(extension);
    758             }
    759             fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
    760             fSetupFragPositionGlobal = true;
    761         }
    762         this->write("gl_FragCoord");
    763     } else {
    764         if (!fSetupFragPositionLocal) {
    765             fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
    766             fFunctionHeader += "    vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
    767                                " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
    768             fSetupFragPositionLocal = true;
    769         }
    770         this->write("sk_FragCoord");
    771     }
    772 }
    773 
    774 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
    775     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
    776         case SK_FRAGCOLOR_BUILTIN:
    777             if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
    778                 this->write("sk_FragColor");
    779             } else {
    780                 this->write("gl_FragColor");
    781             }
    782             break;
    783         case SK_FRAGCOORD_BUILTIN:
    784             this->writeFragCoord();
    785             break;
    786         case SK_WIDTH_BUILTIN:
    787             this->write("u_skRTWidth");
    788             break;
    789         case SK_HEIGHT_BUILTIN:
    790             this->write("u_skRTHeight");
    791             break;
    792         case SK_CLOCKWISE_BUILTIN:
    793             this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
    794             break;
    795         case SK_VERTEXID_BUILTIN:
    796             this->write("gl_VertexID");
    797             break;
    798         case SK_INSTANCEID_BUILTIN:
    799             this->write("gl_InstanceID");
    800             break;
    801         case SK_CLIPDISTANCE_BUILTIN:
    802             this->write("gl_ClipDistance");
    803             break;
    804         case SK_IN_BUILTIN:
    805             this->write("gl_in");
    806             break;
    807         case SK_INVOCATIONID_BUILTIN:
    808             this->write("gl_InvocationID");
    809             break;
    810         case SK_LASTFRAGCOLOR_BUILTIN:
    811             this->write(fProgram.fSettings.fCaps->fbFetchColorName());
    812             break;
    813         default:
    814             this->write(ref.fVariable.fName);
    815     }
    816 }
    817 
    818 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
    819     this->writeExpression(*expr.fBase, kPostfix_Precedence);
    820     this->write("[");
    821     this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
    822     this->write("]");
    823 }
    824 
    825 bool is_sk_position(const FieldAccess& f) {
    826     return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
    827 }
    828 
    829 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
    830     if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
    831         this->writeExpression(*f.fBase, kPostfix_Precedence);
    832         this->write(".");
    833     }
    834     switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
    835         case SK_CLIPDISTANCE_BUILTIN:
    836             this->write("gl_ClipDistance");
    837             break;
    838         default:
    839             StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
    840             if (name == "sk_Position") {
    841                 this->write("gl_Position");
    842             } else if (name == "sk_PointSize") {
    843                 this->write("gl_PointSize");
    844             } else {
    845                 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
    846             }
    847     }
    848 }
    849 
    850 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
    851     int last = swizzle.fComponents.back();
    852     if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
    853         this->writeType(swizzle.fType);
    854         this->write("(");
    855     }
    856     this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
    857     this->write(".");
    858     for (int c : swizzle.fComponents) {
    859         if (c >= 0) {
    860             this->write(&("x\0y\0z\0w\0"[c * 2]));
    861         }
    862     }
    863     if (last == SKSL_SWIZZLE_0) {
    864         this->write(", 0)");
    865     }
    866     else if (last == SKSL_SWIZZLE_1) {
    867         this->write(", 1)");
    868     }
    869 }
    870 
    871 GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
    872     switch (op) {
    873         case Token::STAR:         // fall through
    874         case Token::SLASH:        // fall through
    875         case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
    876         case Token::PLUS:         // fall through
    877         case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
    878         case Token::SHL:          // fall through
    879         case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
    880         case Token::LT:           // fall through
    881         case Token::GT:           // fall through
    882         case Token::LTEQ:         // fall through
    883         case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
    884         case Token::EQEQ:         // fall through
    885         case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
    886         case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
    887         case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
    888         case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
    889         case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
    890         case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
    891         case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
    892         case Token::EQ:           // fall through
    893         case Token::PLUSEQ:       // fall through
    894         case Token::MINUSEQ:      // fall through
    895         case Token::STAREQ:       // fall through
    896         case Token::SLASHEQ:      // fall through
    897         case Token::PERCENTEQ:    // fall through
    898         case Token::SHLEQ:        // fall through
    899         case Token::SHREQ:        // fall through
    900         case Token::LOGICALANDEQ: // fall through
    901         case Token::LOGICALXOREQ: // fall through
    902         case Token::LOGICALOREQ:  // fall through
    903         case Token::BITWISEANDEQ: // fall through
    904         case Token::BITWISEXOREQ: // fall through
    905         case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
    906         case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
    907         default: ABORT("unsupported binary operator");
    908     }
    909 }
    910 
    911 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
    912                                               Precedence parentPrecedence) {
    913     if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
    914             (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
    915         this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
    916         return;
    917     }
    918 
    919     Precedence precedence = GetBinaryPrecedence(b.fOperator);
    920     if (precedence >= parentPrecedence) {
    921         this->write("(");
    922     }
    923     bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
    924                               Compiler::IsAssignment(b.fOperator) &&
    925                               Expression::kFieldAccess_Kind == b.fLeft->fKind &&
    926                               is_sk_position((FieldAccess&) *b.fLeft) &&
    927                               !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
    928                               !fProgram.fSettings.fCaps->canUseFragCoord();
    929     if (positionWorkaround) {
    930         this->write("sk_FragCoord_Workaround = (");
    931     }
    932     this->writeExpression(*b.fLeft, precedence);
    933     this->write(" ");
    934     this->write(Compiler::OperatorName(b.fOperator));
    935     this->write(" ");
    936     this->writeExpression(*b.fRight, precedence);
    937     if (positionWorkaround) {
    938         this->write(")");
    939     }
    940     if (precedence >= parentPrecedence) {
    941         this->write(")");
    942     }
    943 }
    944 
    945 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
    946                                                               Precedence parentPrecedence) {
    947     if (kTernary_Precedence >= parentPrecedence) {
    948         this->write("(");
    949     }
    950 
    951     // Transform:
    952     // a && b  =>   a ? b : false
    953     // a || b  =>   a ? true : b
    954     this->writeExpression(*b.fLeft, kTernary_Precedence);
    955     this->write(" ? ");
    956     if (b.fOperator == Token::LOGICALAND) {
    957         this->writeExpression(*b.fRight, kTernary_Precedence);
    958     } else {
    959         BoolLiteral boolTrue(fContext, -1, true);
    960         this->writeBoolLiteral(boolTrue);
    961     }
    962     this->write(" : ");
    963     if (b.fOperator == Token::LOGICALAND) {
    964         BoolLiteral boolFalse(fContext, -1, false);
    965         this->writeBoolLiteral(boolFalse);
    966     } else {
    967         this->writeExpression(*b.fRight, kTernary_Precedence);
    968     }
    969     if (kTernary_Precedence >= parentPrecedence) {
    970         this->write(")");
    971     }
    972 }
    973 
    974 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
    975                                                Precedence parentPrecedence) {
    976     if (kTernary_Precedence >= parentPrecedence) {
    977         this->write("(");
    978     }
    979     this->writeExpression(*t.fTest, kTernary_Precedence);
    980     this->write(" ? ");
    981     this->writeExpression(*t.fIfTrue, kTernary_Precedence);
    982     this->write(" : ");
    983     this->writeExpression(*t.fIfFalse, kTernary_Precedence);
    984     if (kTernary_Precedence >= parentPrecedence) {
    985         this->write(")");
    986     }
    987 }
    988 
    989 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
    990                                               Precedence parentPrecedence) {
    991     if (kPrefix_Precedence >= parentPrecedence) {
    992         this->write("(");
    993     }
    994     this->write(Compiler::OperatorName(p.fOperator));
    995     this->writeExpression(*p.fOperand, kPrefix_Precedence);
    996     if (kPrefix_Precedence >= parentPrecedence) {
    997         this->write(")");
    998     }
    999 }
   1000 
   1001 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
   1002                                                Precedence parentPrecedence) {
   1003     if (kPostfix_Precedence >= parentPrecedence) {
   1004         this->write("(");
   1005     }
   1006     this->writeExpression(*p.fOperand, kPostfix_Precedence);
   1007     this->write(Compiler::OperatorName(p.fOperator));
   1008     if (kPostfix_Precedence >= parentPrecedence) {
   1009         this->write(")");
   1010     }
   1011 }
   1012 
   1013 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
   1014     this->write(b.fValue ? "true" : "false");
   1015 }
   1016 
   1017 void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
   1018     if (i.fType == *fContext.fUInt_Type) {
   1019         this->write(to_string(i.fValue & 0xffffffff) + "u");
   1020     } else if (i.fType == *fContext.fUShort_Type) {
   1021         this->write(to_string(i.fValue & 0xffff) + "u");
   1022     } else if (i.fType == *fContext.fUByte_Type) {
   1023         this->write(to_string(i.fValue & 0xff) + "u");
   1024     } else {
   1025         this->write(to_string((int32_t) i.fValue));
   1026     }
   1027 }
   1028 
   1029 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
   1030     this->write(to_string(f.fValue));
   1031 }
   1032 
   1033 void GLSLCodeGenerator::writeSetting(const Setting& s) {
   1034     ABORT("internal error; setting was not folded to a constant during compilation\n");
   1035 }
   1036 
   1037 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
   1038     if (fProgramKind != Program::kPipelineStage_Kind) {
   1039         this->writeTypePrecision(f.fDeclaration.fReturnType);
   1040         this->writeType(f.fDeclaration.fReturnType);
   1041         this->write(" " + f.fDeclaration.fName + "(");
   1042         const char* separator = "";
   1043         for (const auto& param : f.fDeclaration.fParameters) {
   1044             this->write(separator);
   1045             separator = ", ";
   1046             this->writeModifiers(param->fModifiers, false);
   1047             std::vector<int> sizes;
   1048             const Type* type = &param->fType;
   1049             while (type->kind() == Type::kArray_Kind) {
   1050                 sizes.push_back(type->columns());
   1051                 type = &type->componentType();
   1052             }
   1053             this->writeTypePrecision(*type);
   1054             this->writeType(*type);
   1055             this->write(" " + param->fName);
   1056             for (int s : sizes) {
   1057                 if (s <= 0) {
   1058                     this->write("[]");
   1059                 } else {
   1060                     this->write("[" + to_string(s) + "]");
   1061                 }
   1062             }
   1063         }
   1064         this->writeLine(") {");
   1065         fIndentation++;
   1066     }
   1067     fFunctionHeader = "";
   1068     OutputStream* oldOut = fOut;
   1069     StringStream buffer;
   1070     fOut = &buffer;
   1071     this->writeStatements(((Block&) *f.fBody).fStatements);
   1072     if (fProgramKind != Program::kPipelineStage_Kind) {
   1073         fIndentation--;
   1074         this->writeLine("}");
   1075     }
   1076 
   1077     fOut = oldOut;
   1078     this->write(fFunctionHeader);
   1079     this->write(buffer.str());
   1080 }
   1081 
   1082 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
   1083                                        bool globalContext) {
   1084     if (modifiers.fFlags & Modifiers::kFlat_Flag) {
   1085         this->write("flat ");
   1086     }
   1087     if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
   1088         this->write("noperspective ");
   1089     }
   1090     String layout = modifiers.fLayout.description();
   1091     if (layout.size()) {
   1092         this->write(layout + " ");
   1093     }
   1094     if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
   1095         this->write("readonly ");
   1096     }
   1097     if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
   1098         this->write("writeonly ");
   1099     }
   1100     if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
   1101         this->write("coherent ");
   1102     }
   1103     if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
   1104         this->write("volatile ");
   1105     }
   1106     if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
   1107         this->write("restrict ");
   1108     }
   1109     if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
   1110         (modifiers.fFlags & Modifiers::kOut_Flag)) {
   1111         this->write("inout ");
   1112     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
   1113         if (globalContext &&
   1114             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
   1115             this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
   1116                                                               : "varying ");
   1117         } else {
   1118             this->write("in ");
   1119         }
   1120     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
   1121         if (globalContext &&
   1122             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
   1123             this->write("varying ");
   1124         } else {
   1125             this->write("out ");
   1126         }
   1127     }
   1128     if (modifiers.fFlags & Modifiers::kUniform_Flag) {
   1129         this->write("uniform ");
   1130     }
   1131     if (modifiers.fFlags & Modifiers::kConst_Flag) {
   1132         this->write("const ");
   1133     }
   1134     if (modifiers.fFlags & Modifiers::kPLS_Flag) {
   1135         this->write("__pixel_localEXT ");
   1136     }
   1137     if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
   1138         this->write("__pixel_local_inEXT ");
   1139     }
   1140     if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
   1141         this->write("__pixel_local_outEXT ");
   1142     }
   1143     switch (modifiers.fLayout.fFormat) {
   1144         case Layout::Format::kUnspecified:
   1145             break;
   1146         case Layout::Format::kRGBA32F: // fall through
   1147         case Layout::Format::kR32F:
   1148             this->write("highp ");
   1149             break;
   1150         case Layout::Format::kRGBA16F: // fall through
   1151         case Layout::Format::kR16F:    // fall through
   1152         case Layout::Format::kRG16F:
   1153             this->write("mediump ");
   1154             break;
   1155         case Layout::Format::kRGBA8:  // fall through
   1156         case Layout::Format::kR8:     // fall through
   1157         case Layout::Format::kRGBA8I: // fall through
   1158         case Layout::Format::kR8I:
   1159             this->write("lowp ");
   1160             break;
   1161     }
   1162 }
   1163 
   1164 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
   1165     if (intf.fTypeName == "sk_PerVertex") {
   1166         return;
   1167     }
   1168     this->writeModifiers(intf.fVariable.fModifiers, true);
   1169     this->writeLine(intf.fTypeName + " {");
   1170     fIndentation++;
   1171     const Type* structType = &intf.fVariable.fType;
   1172     while (structType->kind() == Type::kArray_Kind) {
   1173         structType = &structType->componentType();
   1174     }
   1175     for (const auto& f : structType->fields()) {
   1176         this->writeModifiers(f.fModifiers, false);
   1177         this->writeTypePrecision(*f.fType);
   1178         this->writeType(*f.fType);
   1179         this->writeLine(" " + f.fName + ";");
   1180     }
   1181     fIndentation--;
   1182     this->write("}");
   1183     if (intf.fInstanceName.size()) {
   1184         this->write(" ");
   1185         this->write(intf.fInstanceName);
   1186         for (const auto& size : intf.fSizes) {
   1187             this->write("[");
   1188             if (size) {
   1189                 this->writeExpression(*size, kTopLevel_Precedence);
   1190             }
   1191             this->write("]");
   1192         }
   1193     }
   1194     this->writeLine(";");
   1195 }
   1196 
   1197 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
   1198     this->writeExpression(value, kTopLevel_Precedence);
   1199 }
   1200 
   1201 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
   1202     if (usesPrecisionModifiers()) {
   1203         switch (type.kind()) {
   1204             case Type::kScalar_Kind:
   1205                 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
   1206                     type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
   1207                     if (fProgram.fSettings.fForceHighPrecision ||
   1208                             fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
   1209                         return "highp ";
   1210                     }
   1211                     return "mediump ";
   1212                 }
   1213                 if (type == *fContext.fHalf_Type) {
   1214                     return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
   1215                 }
   1216                 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
   1217                         type == *fContext.fUInt_Type) {
   1218                     return "highp ";
   1219                 }
   1220                 return "";
   1221             case Type::kVector_Kind: // fall through
   1222             case Type::kMatrix_Kind:
   1223                 return this->getTypePrecision(type.componentType());
   1224             default:
   1225                 break;
   1226         }
   1227     }
   1228     return "";
   1229 }
   1230 
   1231 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
   1232     this->write(this->getTypePrecision(type));
   1233 }
   1234 
   1235 void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
   1236     if (!decl.fVars.size()) {
   1237         return;
   1238     }
   1239     bool wroteType = false;
   1240     for (const auto& stmt : decl.fVars) {
   1241         VarDeclaration& var = (VarDeclaration&) *stmt;
   1242         if (wroteType) {
   1243             this->write(", ");
   1244         } else {
   1245             this->writeModifiers(var.fVar->fModifiers, global);
   1246             this->writeTypePrecision(decl.fBaseType);
   1247             this->writeType(decl.fBaseType);
   1248             this->write(" ");
   1249             wroteType = true;
   1250         }
   1251         this->write(var.fVar->fName);
   1252         for (const auto& size : var.fSizes) {
   1253             this->write("[");
   1254             if (size) {
   1255                 this->writeExpression(*size, kTopLevel_Precedence);
   1256             }
   1257             this->write("]");
   1258         }
   1259         if (var.fValue) {
   1260             this->write(" = ");
   1261             this->writeVarInitializer(*var.fVar, *var.fValue);
   1262         }
   1263         if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
   1264             if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
   1265                 this->writeExtension(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
   1266             }
   1267             fFoundImageDecl = true;
   1268         }
   1269         if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
   1270             if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
   1271                 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
   1272             }
   1273             if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
   1274                 this->writeExtension(
   1275                                   fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
   1276             }
   1277             fFoundExternalSamplerDecl = true;
   1278         }
   1279     }
   1280     if (wroteType) {
   1281         this->write(";");
   1282     }
   1283 }
   1284 
   1285 void GLSLCodeGenerator::writeStatement(const Statement& s) {
   1286     switch (s.fKind) {
   1287         case Statement::kBlock_Kind:
   1288             this->writeBlock((Block&) s);
   1289             break;
   1290         case Statement::kExpression_Kind:
   1291             this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
   1292             this->write(";");
   1293             break;
   1294         case Statement::kReturn_Kind:
   1295             this->writeReturnStatement((ReturnStatement&) s);
   1296             break;
   1297         case Statement::kVarDeclarations_Kind:
   1298             this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
   1299             break;
   1300         case Statement::kIf_Kind:
   1301             this->writeIfStatement((IfStatement&) s);
   1302             break;
   1303         case Statement::kFor_Kind:
   1304             this->writeForStatement((ForStatement&) s);
   1305             break;
   1306         case Statement::kWhile_Kind:
   1307             this->writeWhileStatement((WhileStatement&) s);
   1308             break;
   1309         case Statement::kDo_Kind:
   1310             this->writeDoStatement((DoStatement&) s);
   1311             break;
   1312         case Statement::kSwitch_Kind:
   1313             this->writeSwitchStatement((SwitchStatement&) s);
   1314             break;
   1315         case Statement::kBreak_Kind:
   1316             this->write("break;");
   1317             break;
   1318         case Statement::kContinue_Kind:
   1319             this->write("continue;");
   1320             break;
   1321         case Statement::kDiscard_Kind:
   1322             this->write("discard;");
   1323             break;
   1324         case Statement::kNop_Kind:
   1325             this->write(";");
   1326             break;
   1327         default:
   1328             ABORT("unsupported statement: %s", s.description().c_str());
   1329     }
   1330 }
   1331 
   1332 void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
   1333     for (const auto& s : statements) {
   1334         if (!s->isEmpty()) {
   1335             this->writeStatement(*s);
   1336             this->writeLine();
   1337         }
   1338     }
   1339 }
   1340 
   1341 void GLSLCodeGenerator::writeBlock(const Block& b) {
   1342     this->writeLine("{");
   1343     fIndentation++;
   1344     this->writeStatements(b.fStatements);
   1345     fIndentation--;
   1346     this->write("}");
   1347 }
   1348 
   1349 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
   1350     this->write("if (");
   1351     this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
   1352     this->write(") ");
   1353     this->writeStatement(*stmt.fIfTrue);
   1354     if (stmt.fIfFalse) {
   1355         this->write(" else ");
   1356         this->writeStatement(*stmt.fIfFalse);
   1357     }
   1358 }
   1359 
   1360 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
   1361     this->write("for (");
   1362     if (f.fInitializer && !f.fInitializer->isEmpty()) {
   1363         this->writeStatement(*f.fInitializer);
   1364     } else {
   1365         this->write("; ");
   1366     }
   1367     if (f.fTest) {
   1368         if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
   1369             std::unique_ptr<Expression> and_true(new BinaryExpression(
   1370                     -1, f.fTest->clone(), Token::LOGICALAND,
   1371                     std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
   1372                                                                  true)),
   1373                     *fContext.fBool_Type));
   1374             this->writeExpression(*and_true, kTopLevel_Precedence);
   1375         } else {
   1376             this->writeExpression(*f.fTest, kTopLevel_Precedence);
   1377         }
   1378     }
   1379     this->write("; ");
   1380     if (f.fNext) {
   1381         this->writeExpression(*f.fNext, kTopLevel_Precedence);
   1382     }
   1383     this->write(") ");
   1384     this->writeStatement(*f.fStatement);
   1385 }
   1386 
   1387 void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
   1388     this->write("while (");
   1389     this->writeExpression(*w.fTest, kTopLevel_Precedence);
   1390     this->write(") ");
   1391     this->writeStatement(*w.fStatement);
   1392 }
   1393 
   1394 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
   1395     if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
   1396         this->write("do ");
   1397         this->writeStatement(*d.fStatement);
   1398         this->write(" while (");
   1399         this->writeExpression(*d.fTest, kTopLevel_Precedence);
   1400         this->write(");");
   1401         return;
   1402     }
   1403 
   1404     // Otherwise, do the do while loop workaround, to rewrite loops of the form:
   1405     //     do {
   1406     //         CODE;
   1407     //     } while (CONDITION)
   1408     //
   1409     // to loops of the form
   1410     //     bool temp = false;
   1411     //     while (true) {
   1412     //         if (temp) {
   1413     //             if (!CONDITION) {
   1414     //                 break;
   1415     //             }
   1416     //         }
   1417     //         temp = true;
   1418     //         CODE;
   1419     //     }
   1420     String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
   1421     this->write("bool ");
   1422     this->write(tmpVar);
   1423     this->writeLine(" = false;");
   1424     this->writeLine("while (true) {");
   1425     fIndentation++;
   1426     this->write("if (");
   1427     this->write(tmpVar);
   1428     this->writeLine(") {");
   1429     fIndentation++;
   1430     this->write("if (!");
   1431     this->writeExpression(*d.fTest, kPrefix_Precedence);
   1432     this->writeLine(") {");
   1433     fIndentation++;
   1434     this->writeLine("break;");
   1435     fIndentation--;
   1436     this->writeLine("}");
   1437     fIndentation--;
   1438     this->writeLine("}");
   1439     this->write(tmpVar);
   1440     this->writeLine(" = true;");
   1441     this->writeStatement(*d.fStatement);
   1442     this->writeLine();
   1443     fIndentation--;
   1444     this->write("}");
   1445 }
   1446 
   1447 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
   1448     this->write("switch (");
   1449     this->writeExpression(*s.fValue, kTopLevel_Precedence);
   1450     this->writeLine(") {");
   1451     fIndentation++;
   1452     for (const auto& c : s.fCases) {
   1453         if (c->fValue) {
   1454             this->write("case ");
   1455             this->writeExpression(*c->fValue, kTopLevel_Precedence);
   1456             this->writeLine(":");
   1457         } else {
   1458             this->writeLine("default:");
   1459         }
   1460         fIndentation++;
   1461         for (const auto& stmt : c->fStatements) {
   1462             this->writeStatement(*stmt);
   1463             this->writeLine();
   1464         }
   1465         fIndentation--;
   1466     }
   1467     fIndentation--;
   1468     this->write("}");
   1469 }
   1470 
   1471 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
   1472     this->write("return");
   1473     if (r.fExpression) {
   1474         this->write(" ");
   1475         this->writeExpression(*r.fExpression, kTopLevel_Precedence);
   1476     }
   1477     this->write(";");
   1478 }
   1479 
   1480 void GLSLCodeGenerator::writeHeader() {
   1481     this->write(fProgram.fSettings.fCaps->versionDeclString());
   1482     this->writeLine();
   1483 }
   1484 
   1485 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
   1486     switch (e.fKind) {
   1487         case ProgramElement::kExtension_Kind:
   1488             this->writeExtension(((Extension&) e).fName);
   1489             break;
   1490         case ProgramElement::kVar_Kind: {
   1491             VarDeclarations& decl = (VarDeclarations&) e;
   1492             if (decl.fVars.size() > 0) {
   1493                 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
   1494                 if (builtin == -1) {
   1495                     // normal var
   1496                     this->writeVarDeclarations(decl, true);
   1497                     this->writeLine();
   1498                 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
   1499                            fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
   1500                            ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
   1501                     if (fProgram.fSettings.fFragColorIsInOut) {
   1502                         this->write("inout ");
   1503                     } else {
   1504                         this->write("out ");
   1505                     }
   1506                     if (usesPrecisionModifiers()) {
   1507                         this->write("mediump ");
   1508                     }
   1509                     this->writeLine("vec4 sk_FragColor;");
   1510                 }
   1511             }
   1512             break;
   1513         }
   1514         case ProgramElement::kInterfaceBlock_Kind:
   1515             this->writeInterfaceBlock((InterfaceBlock&) e);
   1516             break;
   1517         case ProgramElement::kFunction_Kind:
   1518             this->writeFunction((FunctionDefinition&) e);
   1519             break;
   1520         case ProgramElement::kModifiers_Kind: {
   1521             const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
   1522             if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
   1523                 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
   1524                     this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
   1525                 }
   1526                 fFoundGSInvocations = true;
   1527             }
   1528             this->writeModifiers(modifiers, true);
   1529             this->writeLine(";");
   1530             break;
   1531         }
   1532         case ProgramElement::kEnum_Kind:
   1533             break;
   1534         default:
   1535             printf("%s\n", e.description().c_str());
   1536             ABORT("unsupported program element");
   1537     }
   1538 }
   1539 
   1540 void GLSLCodeGenerator::writeInputVars() {
   1541     if (fProgram.fInputs.fRTWidth) {
   1542         const char* precision = usesPrecisionModifiers() ? "highp " : "";
   1543         fGlobals.writeText("uniform ");
   1544         fGlobals.writeText(precision);
   1545         fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
   1546     }
   1547     if (fProgram.fInputs.fRTHeight) {
   1548         const char* precision = usesPrecisionModifiers() ? "highp " : "";
   1549         fGlobals.writeText("uniform ");
   1550         fGlobals.writeText(precision);
   1551         fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
   1552     }
   1553 }
   1554 
   1555 bool GLSLCodeGenerator::generateCode() {
   1556     if (fProgramKind != Program::kPipelineStage_Kind) {
   1557         this->writeHeader();
   1558     }
   1559     if (Program::kGeometry_Kind == fProgramKind &&
   1560         fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
   1561         this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
   1562     }
   1563     OutputStream* rawOut = fOut;
   1564     StringStream body;
   1565     fOut = &body;
   1566     for (const auto& e : fProgram) {
   1567         this->writeProgramElement(e);
   1568     }
   1569     fOut = rawOut;
   1570 
   1571     write_stringstream(fExtensions, *rawOut);
   1572     this->writeInputVars();
   1573     write_stringstream(fGlobals, *rawOut);
   1574 
   1575     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
   1576         Layout layout;
   1577         switch (fProgram.fKind) {
   1578             case Program::kVertex_Kind: {
   1579                 Modifiers modifiers(layout, Modifiers::kOut_Flag);
   1580                 this->writeModifiers(modifiers, true);
   1581                 if (this->usesPrecisionModifiers()) {
   1582                     this->write("highp ");
   1583                 }
   1584                 this->write("vec4 sk_FragCoord_Workaround;\n");
   1585                 break;
   1586             }
   1587             case Program::kFragment_Kind: {
   1588                 Modifiers modifiers(layout, Modifiers::kIn_Flag);
   1589                 this->writeModifiers(modifiers, true);
   1590                 if (this->usesPrecisionModifiers()) {
   1591                     this->write("highp ");
   1592                 }
   1593                 this->write("vec4 sk_FragCoord_Workaround;\n");
   1594                 break;
   1595             }
   1596             default:
   1597                 break;
   1598         }
   1599     }
   1600 
   1601     if (this->usesPrecisionModifiers()) {
   1602         this->writeLine("precision mediump float;");
   1603     }
   1604     write_stringstream(fExtraFunctions, *rawOut);
   1605     write_stringstream(body, *rawOut);
   1606     return true;
   1607 }
   1608 
   1609 }
   1610