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