• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         default:
157             return type.name();
158     }
159 }
160 
writeType(const Type & type)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 
writeExpression(const Expression & expr,Precedence parentPrecedence)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 
is_abs(Expression & expr)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.
writeMinAbsHack(Expression & absExpr,Expression & otherExpr)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 
writeInverseSqrtHack(const Expression & x)264 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
265     this->write("(1.0 / sqrt(");
266     this->writeExpression(x, kTopLevel_Precedence);
267     this->write("))");
268 }
269 
writeDeterminantHack(const Expression & mat)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 
writeInverseHack(const Expression & mat)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 
writeTransposeHack(const Expression & mat)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 
writeFunctionCall(const FunctionCall & c)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)["sample"]      = 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                 if (fTextureFunctionOverride != "") {
674                     this->write(fTextureFunctionOverride.c_str());
675                 } else {
676                     this->write("texture");
677                     if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
678                         this->write(dim);
679                     }
680                     if (proj) {
681                         this->write("Proj");
682                     }
683                 }
684                 nameWritten = true;
685                 break;
686             }
687             case FunctionClass::kTranspose:
688                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
689                     SkASSERT(c.fArguments.size() == 1);
690                     this->writeTransposeHack(*c.fArguments[0]);
691                     return;
692                 }
693                 break;
694         }
695     }
696     if (!nameWritten) {
697         this->write(c.fFunction.fName);
698     }
699     this->write("(");
700     const char* separator = "";
701     for (const auto& arg : c.fArguments) {
702         this->write(separator);
703         separator = ", ";
704         this->writeExpression(*arg, kSequence_Precedence);
705     }
706     if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
707         this->write(", -0.5");
708     }
709     this->write(")");
710 }
711 
712 void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
713     if (c.fArguments.size() == 1 &&
714         (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
715         (c.fType.kind() == Type::kScalar_Kind &&
716          c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
717         // in cases like half(float), they're different types as far as SkSL is concerned but the
718         // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
719         // out the inner expression here.
720         this->writeExpression(*c.fArguments[0], parentPrecedence);
721         return;
722     }
723     this->writeType(c.fType);
724     this->write("(");
725     const char* separator = "";
726     for (const auto& arg : c.fArguments) {
727         this->write(separator);
728         separator = ", ";
729         this->writeExpression(*arg, kSequence_Precedence);
730     }
731     this->write(")");
732 }
733 
734 void GLSLCodeGenerator::writeFragCoord() {
735     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
736         if (!fSetupFragCoordWorkaround) {
737             const char* precision = usesPrecisionModifiers() ? "highp " : "";
738             fFunctionHeader += precision;
739             fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
740             fFunctionHeader += precision;
741             fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
742                 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
743             // Ensure that we get exact .5 values for x and y.
744             fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
745                                "vec2(.5);\n";
746             fSetupFragCoordWorkaround = true;
747         }
748         this->write("sk_FragCoord_Resolved");
749         return;
750     }
751 
752     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
753     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
754     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
755     if (!fProgram.fSettings.fFlipY) {
756         this->write("gl_FragCoord");
757     } else if (const char* extension =
758                                   fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
759         if (!fSetupFragPositionGlobal) {
760             if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
761                 this->writeExtension(extension);
762             }
763             fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
764             fSetupFragPositionGlobal = true;
765         }
766         this->write("gl_FragCoord");
767     } else {
768         if (!fSetupFragPositionLocal) {
769             fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
770             fFunctionHeader += "    vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
771                                " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
772             fSetupFragPositionLocal = true;
773         }
774         this->write("sk_FragCoord");
775     }
776 }
777 
778 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
779     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
780         case SK_FRAGCOLOR_BUILTIN:
781             if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
782                 this->write("sk_FragColor");
783             } else {
784                 this->write("gl_FragColor");
785             }
786             break;
787         case SK_FRAGCOORD_BUILTIN:
788             this->writeFragCoord();
789             break;
790         case SK_WIDTH_BUILTIN:
791             this->write("u_skRTWidth");
792             break;
793         case SK_HEIGHT_BUILTIN:
794             this->write("u_skRTHeight");
795             break;
796         case SK_CLOCKWISE_BUILTIN:
797             this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
798             break;
799         case SK_VERTEXID_BUILTIN:
800             this->write("gl_VertexID");
801             break;
802         case SK_INSTANCEID_BUILTIN:
803             this->write("gl_InstanceID");
804             break;
805         case SK_CLIPDISTANCE_BUILTIN:
806             this->write("gl_ClipDistance");
807             break;
808         case SK_IN_BUILTIN:
809             this->write("gl_in");
810             break;
811         case SK_INVOCATIONID_BUILTIN:
812             this->write("gl_InvocationID");
813             break;
814         case SK_LASTFRAGCOLOR_BUILTIN:
815             this->write(fProgram.fSettings.fCaps->fbFetchColorName());
816             break;
817         default:
818             this->write(ref.fVariable.fName);
819     }
820 }
821 
822 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
823     this->writeExpression(*expr.fBase, kPostfix_Precedence);
824     this->write("[");
825     this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
826     this->write("]");
827 }
828 
829 bool is_sk_position(const FieldAccess& f) {
830     return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
831 }
832 
833 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
834     if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
835         this->writeExpression(*f.fBase, kPostfix_Precedence);
836         this->write(".");
837     }
838     switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
839         case SK_CLIPDISTANCE_BUILTIN:
840             this->write("gl_ClipDistance");
841             break;
842         default:
843             StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
844             if (name == "sk_Position") {
845                 this->write("gl_Position");
846             } else if (name == "sk_PointSize") {
847                 this->write("gl_PointSize");
848             } else {
849                 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
850             }
851     }
852 }
853 
854 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
855     int last = swizzle.fComponents.back();
856     if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
857         this->writeType(swizzle.fType);
858         this->write("(");
859     }
860     this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
861     this->write(".");
862     for (int c : swizzle.fComponents) {
863         if (c >= 0) {
864             this->write(&("x\0y\0z\0w\0"[c * 2]));
865         }
866     }
867     if (last == SKSL_SWIZZLE_0) {
868         this->write(", 0)");
869     }
870     else if (last == SKSL_SWIZZLE_1) {
871         this->write(", 1)");
872     }
873 }
874 
875 GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
876     switch (op) {
877         case Token::STAR:         // fall through
878         case Token::SLASH:        // fall through
879         case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
880         case Token::PLUS:         // fall through
881         case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
882         case Token::SHL:          // fall through
883         case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
884         case Token::LT:           // fall through
885         case Token::GT:           // fall through
886         case Token::LTEQ:         // fall through
887         case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
888         case Token::EQEQ:         // fall through
889         case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
890         case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
891         case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
892         case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
893         case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
894         case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
895         case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
896         case Token::EQ:           // fall through
897         case Token::PLUSEQ:       // fall through
898         case Token::MINUSEQ:      // fall through
899         case Token::STAREQ:       // fall through
900         case Token::SLASHEQ:      // fall through
901         case Token::PERCENTEQ:    // fall through
902         case Token::SHLEQ:        // fall through
903         case Token::SHREQ:        // fall through
904         case Token::LOGICALANDEQ: // fall through
905         case Token::LOGICALXOREQ: // fall through
906         case Token::LOGICALOREQ:  // fall through
907         case Token::BITWISEANDEQ: // fall through
908         case Token::BITWISEXOREQ: // fall through
909         case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
910         case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
911         default: ABORT("unsupported binary operator");
912     }
913 }
914 
915 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
916                                               Precedence parentPrecedence) {
917     if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
918             (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
919         this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
920         return;
921     }
922 
923     Precedence precedence = GetBinaryPrecedence(b.fOperator);
924     if (precedence >= parentPrecedence) {
925         this->write("(");
926     }
927     bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
928                               Compiler::IsAssignment(b.fOperator) &&
929                               Expression::kFieldAccess_Kind == b.fLeft->fKind &&
930                               is_sk_position((FieldAccess&) *b.fLeft) &&
931                               !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
932                               !fProgram.fSettings.fCaps->canUseFragCoord();
933     if (positionWorkaround) {
934         this->write("sk_FragCoord_Workaround = (");
935     }
936     this->writeExpression(*b.fLeft, precedence);
937     this->write(" ");
938     this->write(Compiler::OperatorName(b.fOperator));
939     this->write(" ");
940     this->writeExpression(*b.fRight, precedence);
941     if (positionWorkaround) {
942         this->write(")");
943     }
944     if (precedence >= parentPrecedence) {
945         this->write(")");
946     }
947 }
948 
949 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
950                                                               Precedence parentPrecedence) {
951     if (kTernary_Precedence >= parentPrecedence) {
952         this->write("(");
953     }
954 
955     // Transform:
956     // a && b  =>   a ? b : false
957     // a || b  =>   a ? true : b
958     this->writeExpression(*b.fLeft, kTernary_Precedence);
959     this->write(" ? ");
960     if (b.fOperator == Token::LOGICALAND) {
961         this->writeExpression(*b.fRight, kTernary_Precedence);
962     } else {
963         BoolLiteral boolTrue(fContext, -1, true);
964         this->writeBoolLiteral(boolTrue);
965     }
966     this->write(" : ");
967     if (b.fOperator == Token::LOGICALAND) {
968         BoolLiteral boolFalse(fContext, -1, false);
969         this->writeBoolLiteral(boolFalse);
970     } else {
971         this->writeExpression(*b.fRight, kTernary_Precedence);
972     }
973     if (kTernary_Precedence >= parentPrecedence) {
974         this->write(")");
975     }
976 }
977 
978 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
979                                                Precedence parentPrecedence) {
980     if (kTernary_Precedence >= parentPrecedence) {
981         this->write("(");
982     }
983     this->writeExpression(*t.fTest, kTernary_Precedence);
984     this->write(" ? ");
985     this->writeExpression(*t.fIfTrue, kTernary_Precedence);
986     this->write(" : ");
987     this->writeExpression(*t.fIfFalse, kTernary_Precedence);
988     if (kTernary_Precedence >= parentPrecedence) {
989         this->write(")");
990     }
991 }
992 
993 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
994                                               Precedence parentPrecedence) {
995     if (kPrefix_Precedence >= parentPrecedence) {
996         this->write("(");
997     }
998     this->write(Compiler::OperatorName(p.fOperator));
999     this->writeExpression(*p.fOperand, kPrefix_Precedence);
1000     if (kPrefix_Precedence >= parentPrecedence) {
1001         this->write(")");
1002     }
1003 }
1004 
1005 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
1006                                                Precedence parentPrecedence) {
1007     if (kPostfix_Precedence >= parentPrecedence) {
1008         this->write("(");
1009     }
1010     this->writeExpression(*p.fOperand, kPostfix_Precedence);
1011     this->write(Compiler::OperatorName(p.fOperator));
1012     if (kPostfix_Precedence >= parentPrecedence) {
1013         this->write(")");
1014     }
1015 }
1016 
1017 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1018     this->write(b.fValue ? "true" : "false");
1019 }
1020 
1021 void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1022     if (i.fType == *fContext.fUInt_Type) {
1023         this->write(to_string(i.fValue & 0xffffffff) + "u");
1024     } else if (i.fType == *fContext.fUShort_Type) {
1025         this->write(to_string(i.fValue & 0xffff) + "u");
1026     } else if (i.fType == *fContext.fUByte_Type) {
1027         this->write(to_string(i.fValue & 0xff) + "u");
1028     } else {
1029         this->write(to_string((int32_t) i.fValue));
1030     }
1031 }
1032 
1033 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1034     this->write(to_string(f.fValue));
1035 }
1036 
1037 void GLSLCodeGenerator::writeSetting(const Setting& s) {
1038     ABORT("internal error; setting was not folded to a constant during compilation\n");
1039 }
1040 
1041 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1042     fSetupFragPositionLocal = false;
1043     fSetupFragCoordWorkaround = false;
1044     if (fProgramKind != Program::kPipelineStage_Kind) {
1045         this->writeTypePrecision(f.fDeclaration.fReturnType);
1046         this->writeType(f.fDeclaration.fReturnType);
1047         this->write(" " + f.fDeclaration.fName + "(");
1048         const char* separator = "";
1049         for (const auto& param : f.fDeclaration.fParameters) {
1050             this->write(separator);
1051             separator = ", ";
1052             this->writeModifiers(param->fModifiers, false);
1053             std::vector<int> sizes;
1054             const Type* type = &param->fType;
1055             while (type->kind() == Type::kArray_Kind) {
1056                 sizes.push_back(type->columns());
1057                 type = &type->componentType();
1058             }
1059             this->writeTypePrecision(*type);
1060             this->writeType(*type);
1061             this->write(" " + param->fName);
1062             for (int s : sizes) {
1063                 if (s <= 0) {
1064                     this->write("[]");
1065                 } else {
1066                     this->write("[" + to_string(s) + "]");
1067                 }
1068             }
1069         }
1070         this->writeLine(") {");
1071         fIndentation++;
1072     }
1073     fFunctionHeader = "";
1074     OutputStream* oldOut = fOut;
1075     StringStream buffer;
1076     fOut = &buffer;
1077     this->writeStatements(((Block&) *f.fBody).fStatements);
1078     if (fProgramKind != Program::kPipelineStage_Kind) {
1079         fIndentation--;
1080         this->writeLine("}");
1081     }
1082 
1083     fOut = oldOut;
1084     this->write(fFunctionHeader);
1085     this->write(buffer.str());
1086 }
1087 
1088 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
1089                                        bool globalContext) {
1090     if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1091         this->write("flat ");
1092     }
1093     if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1094         this->write("noperspective ");
1095     }
1096     String layout = modifiers.fLayout.description();
1097     if (layout.size()) {
1098         this->write(layout + " ");
1099     }
1100     if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1101         this->write("readonly ");
1102     }
1103     if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1104         this->write("writeonly ");
1105     }
1106     if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1107         this->write("coherent ");
1108     }
1109     if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1110         this->write("volatile ");
1111     }
1112     if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1113         this->write("restrict ");
1114     }
1115     if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
1116         (modifiers.fFlags & Modifiers::kOut_Flag)) {
1117         this->write("inout ");
1118     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
1119         if (globalContext &&
1120             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1121             this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1122                                                               : "varying ");
1123         } else {
1124             this->write("in ");
1125         }
1126     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1127         if (globalContext &&
1128             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1129             this->write("varying ");
1130         } else {
1131             this->write("out ");
1132         }
1133     }
1134     if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1135         this->write("uniform ");
1136     }
1137     if (modifiers.fFlags & Modifiers::kConst_Flag) {
1138         this->write("const ");
1139     }
1140     if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1141         this->write("__pixel_localEXT ");
1142     }
1143     if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1144         this->write("__pixel_local_inEXT ");
1145     }
1146     if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1147         this->write("__pixel_local_outEXT ");
1148     }
1149     switch (modifiers.fLayout.fFormat) {
1150         case Layout::Format::kUnspecified:
1151             break;
1152         case Layout::Format::kRGBA32F:      // fall through
1153         case Layout::Format::kR32F:
1154             this->write("highp ");
1155             break;
1156         case Layout::Format::kRGBA16F:      // fall through
1157         case Layout::Format::kR16F:         // fall through
1158         case Layout::Format::kLUMINANCE16F: // fall through
1159         case Layout::Format::kRG16F:
1160             this->write("mediump ");
1161             break;
1162         case Layout::Format::kRGBA8:        // fall through
1163         case Layout::Format::kR8:           // fall through
1164         case Layout::Format::kRGBA8I:       // fall through
1165         case Layout::Format::kR8I:
1166             this->write("lowp ");
1167             break;
1168     }
1169 }
1170 
1171 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1172     if (intf.fTypeName == "sk_PerVertex") {
1173         return;
1174     }
1175     this->writeModifiers(intf.fVariable.fModifiers, true);
1176     this->writeLine(intf.fTypeName + " {");
1177     fIndentation++;
1178     const Type* structType = &intf.fVariable.fType;
1179     while (structType->kind() == Type::kArray_Kind) {
1180         structType = &structType->componentType();
1181     }
1182     for (const auto& f : structType->fields()) {
1183         this->writeModifiers(f.fModifiers, false);
1184         this->writeTypePrecision(*f.fType);
1185         this->writeType(*f.fType);
1186         this->writeLine(" " + f.fName + ";");
1187     }
1188     fIndentation--;
1189     this->write("}");
1190     if (intf.fInstanceName.size()) {
1191         this->write(" ");
1192         this->write(intf.fInstanceName);
1193         for (const auto& size : intf.fSizes) {
1194             this->write("[");
1195             if (size) {
1196                 this->writeExpression(*size, kTopLevel_Precedence);
1197             }
1198             this->write("]");
1199         }
1200     }
1201     this->writeLine(";");
1202 }
1203 
1204 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1205     this->writeExpression(value, kTopLevel_Precedence);
1206 }
1207 
1208 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1209     if (usesPrecisionModifiers()) {
1210         switch (type.kind()) {
1211             case Type::kScalar_Kind:
1212                 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1213                     type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
1214                     if (fProgram.fSettings.fForceHighPrecision ||
1215                             fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1216                         return "highp ";
1217                     }
1218                     return "mediump ";
1219                 }
1220                 if (type == *fContext.fHalf_Type) {
1221                     return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
1222                 }
1223                 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1224                         type == *fContext.fUInt_Type) {
1225                     return "highp ";
1226                 }
1227                 return "";
1228             case Type::kVector_Kind: // fall through
1229             case Type::kMatrix_Kind:
1230                 return this->getTypePrecision(type.componentType());
1231             default:
1232                 break;
1233         }
1234     }
1235     return "";
1236 }
1237 
1238 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1239     this->write(this->getTypePrecision(type));
1240 }
1241 
1242 void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
1243     if (!decl.fVars.size()) {
1244         return;
1245     }
1246     bool wroteType = false;
1247     for (const auto& stmt : decl.fVars) {
1248         VarDeclaration& var = (VarDeclaration&) *stmt;
1249         if (wroteType) {
1250             this->write(", ");
1251         } else {
1252             this->writeModifiers(var.fVar->fModifiers, global);
1253             this->writeTypePrecision(decl.fBaseType);
1254             this->writeType(decl.fBaseType);
1255             this->write(" ");
1256             wroteType = true;
1257         }
1258         this->write(var.fVar->fName);
1259         for (const auto& size : var.fSizes) {
1260             this->write("[");
1261             if (size) {
1262                 this->writeExpression(*size, kTopLevel_Precedence);
1263             }
1264             this->write("]");
1265         }
1266         if (var.fValue) {
1267             this->write(" = ");
1268             this->writeVarInitializer(*var.fVar, *var.fValue);
1269         }
1270         if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1271             if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
1272                 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
1273             }
1274             if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
1275                 this->writeExtension(
1276                                   fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
1277             }
1278             fFoundExternalSamplerDecl = true;
1279         }
1280         if (!fFoundRectSamplerDecl && var.fVar->fType == *fContext.fSampler2DRect_Type) {
1281             fFoundRectSamplerDecl = true;
1282         }
1283     }
1284     if (wroteType) {
1285         this->write(";");
1286     }
1287 }
1288 
1289 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1290     switch (s.fKind) {
1291         case Statement::kBlock_Kind:
1292             this->writeBlock((Block&) s);
1293             break;
1294         case Statement::kExpression_Kind:
1295             this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1296             this->write(";");
1297             break;
1298         case Statement::kReturn_Kind:
1299             this->writeReturnStatement((ReturnStatement&) s);
1300             break;
1301         case Statement::kVarDeclarations_Kind:
1302             this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
1303             break;
1304         case Statement::kIf_Kind:
1305             this->writeIfStatement((IfStatement&) s);
1306             break;
1307         case Statement::kFor_Kind:
1308             this->writeForStatement((ForStatement&) s);
1309             break;
1310         case Statement::kWhile_Kind:
1311             this->writeWhileStatement((WhileStatement&) s);
1312             break;
1313         case Statement::kDo_Kind:
1314             this->writeDoStatement((DoStatement&) s);
1315             break;
1316         case Statement::kSwitch_Kind:
1317             this->writeSwitchStatement((SwitchStatement&) s);
1318             break;
1319         case Statement::kBreak_Kind:
1320             this->write("break;");
1321             break;
1322         case Statement::kContinue_Kind:
1323             this->write("continue;");
1324             break;
1325         case Statement::kDiscard_Kind:
1326             this->write("discard;");
1327             break;
1328         case Statement::kNop_Kind:
1329             this->write(";");
1330             break;
1331         default:
1332             ABORT("unsupported statement: %s", s.description().c_str());
1333     }
1334 }
1335 
1336 void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1337     for (const auto& s : statements) {
1338         if (!s->isEmpty()) {
1339             this->writeStatement(*s);
1340             this->writeLine();
1341         }
1342     }
1343 }
1344 
1345 void GLSLCodeGenerator::writeBlock(const Block& b) {
1346     this->writeLine("{");
1347     fIndentation++;
1348     this->writeStatements(b.fStatements);
1349     fIndentation--;
1350     this->write("}");
1351 }
1352 
1353 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1354     this->write("if (");
1355     this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1356     this->write(") ");
1357     this->writeStatement(*stmt.fIfTrue);
1358     if (stmt.fIfFalse) {
1359         this->write(" else ");
1360         this->writeStatement(*stmt.fIfFalse);
1361     }
1362 }
1363 
1364 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1365     this->write("for (");
1366     if (f.fInitializer && !f.fInitializer->isEmpty()) {
1367         this->writeStatement(*f.fInitializer);
1368     } else {
1369         this->write("; ");
1370     }
1371     if (f.fTest) {
1372         if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1373             std::unique_ptr<Expression> and_true(new BinaryExpression(
1374                     -1, f.fTest->clone(), Token::LOGICALAND,
1375                     std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1376                                                                  true)),
1377                     *fContext.fBool_Type));
1378             this->writeExpression(*and_true, kTopLevel_Precedence);
1379         } else {
1380             this->writeExpression(*f.fTest, kTopLevel_Precedence);
1381         }
1382     }
1383     this->write("; ");
1384     if (f.fNext) {
1385         this->writeExpression(*f.fNext, kTopLevel_Precedence);
1386     }
1387     this->write(") ");
1388     this->writeStatement(*f.fStatement);
1389 }
1390 
1391 void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1392     this->write("while (");
1393     this->writeExpression(*w.fTest, kTopLevel_Precedence);
1394     this->write(") ");
1395     this->writeStatement(*w.fStatement);
1396 }
1397 
1398 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1399     if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1400         this->write("do ");
1401         this->writeStatement(*d.fStatement);
1402         this->write(" while (");
1403         this->writeExpression(*d.fTest, kTopLevel_Precedence);
1404         this->write(");");
1405         return;
1406     }
1407 
1408     // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1409     //     do {
1410     //         CODE;
1411     //     } while (CONDITION)
1412     //
1413     // to loops of the form
1414     //     bool temp = false;
1415     //     while (true) {
1416     //         if (temp) {
1417     //             if (!CONDITION) {
1418     //                 break;
1419     //             }
1420     //         }
1421     //         temp = true;
1422     //         CODE;
1423     //     }
1424     String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1425     this->write("bool ");
1426     this->write(tmpVar);
1427     this->writeLine(" = false;");
1428     this->writeLine("while (true) {");
1429     fIndentation++;
1430     this->write("if (");
1431     this->write(tmpVar);
1432     this->writeLine(") {");
1433     fIndentation++;
1434     this->write("if (!");
1435     this->writeExpression(*d.fTest, kPrefix_Precedence);
1436     this->writeLine(") {");
1437     fIndentation++;
1438     this->writeLine("break;");
1439     fIndentation--;
1440     this->writeLine("}");
1441     fIndentation--;
1442     this->writeLine("}");
1443     this->write(tmpVar);
1444     this->writeLine(" = true;");
1445     this->writeStatement(*d.fStatement);
1446     this->writeLine();
1447     fIndentation--;
1448     this->write("}");
1449 }
1450 
1451 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1452     this->write("switch (");
1453     this->writeExpression(*s.fValue, kTopLevel_Precedence);
1454     this->writeLine(") {");
1455     fIndentation++;
1456     for (const auto& c : s.fCases) {
1457         if (c->fValue) {
1458             this->write("case ");
1459             this->writeExpression(*c->fValue, kTopLevel_Precedence);
1460             this->writeLine(":");
1461         } else {
1462             this->writeLine("default:");
1463         }
1464         fIndentation++;
1465         for (const auto& stmt : c->fStatements) {
1466             this->writeStatement(*stmt);
1467             this->writeLine();
1468         }
1469         fIndentation--;
1470     }
1471     fIndentation--;
1472     this->write("}");
1473 }
1474 
1475 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1476     this->write("return");
1477     if (r.fExpression) {
1478         this->write(" ");
1479         this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1480     }
1481     this->write(";");
1482 }
1483 
1484 void GLSLCodeGenerator::writeHeader() {
1485     this->write(fProgram.fSettings.fCaps->versionDeclString());
1486     this->writeLine();
1487 }
1488 
1489 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1490     switch (e.fKind) {
1491         case ProgramElement::kExtension_Kind:
1492             this->writeExtension(((Extension&) e).fName);
1493             break;
1494         case ProgramElement::kVar_Kind: {
1495             VarDeclarations& decl = (VarDeclarations&) e;
1496             if (decl.fVars.size() > 0) {
1497                 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
1498                 if (builtin == -1) {
1499                     // normal var
1500                     this->writeVarDeclarations(decl, true);
1501                     this->writeLine();
1502                 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1503                            fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
1504                            ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
1505                     if (fProgram.fSettings.fFragColorIsInOut) {
1506                         this->write("inout ");
1507                     } else {
1508                         this->write("out ");
1509                     }
1510                     if (usesPrecisionModifiers()) {
1511                         this->write("mediump ");
1512                     }
1513                     this->writeLine("vec4 sk_FragColor;");
1514                 }
1515             }
1516             break;
1517         }
1518         case ProgramElement::kInterfaceBlock_Kind:
1519             this->writeInterfaceBlock((InterfaceBlock&) e);
1520             break;
1521         case ProgramElement::kFunction_Kind:
1522             this->writeFunction((FunctionDefinition&) e);
1523             break;
1524         case ProgramElement::kModifiers_Kind: {
1525             const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1526             if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1527                 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
1528                     this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
1529                 }
1530                 fFoundGSInvocations = true;
1531             }
1532             this->writeModifiers(modifiers, true);
1533             this->writeLine(";");
1534             break;
1535         }
1536         case ProgramElement::kEnum_Kind:
1537             break;
1538         default:
1539             printf("%s\n", e.description().c_str());
1540             ABORT("unsupported program element");
1541     }
1542 }
1543 
1544 void GLSLCodeGenerator::writeInputVars() {
1545     if (fProgram.fInputs.fRTWidth) {
1546         const char* precision = usesPrecisionModifiers() ? "highp " : "";
1547         fGlobals.writeText("uniform ");
1548         fGlobals.writeText(precision);
1549         fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1550     }
1551     if (fProgram.fInputs.fRTHeight) {
1552         const char* precision = usesPrecisionModifiers() ? "highp " : "";
1553         fGlobals.writeText("uniform ");
1554         fGlobals.writeText(precision);
1555         fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1556     }
1557 }
1558 
1559 bool GLSLCodeGenerator::generateCode() {
1560     if (fProgramKind != Program::kPipelineStage_Kind) {
1561         this->writeHeader();
1562     }
1563     if (Program::kGeometry_Kind == fProgramKind &&
1564         fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
1565         this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
1566     }
1567     OutputStream* rawOut = fOut;
1568     StringStream body;
1569     fOut = &body;
1570     for (const auto& e : fProgram) {
1571         this->writeProgramElement(e);
1572     }
1573     fOut = rawOut;
1574 
1575     write_stringstream(fExtensions, *rawOut);
1576     this->writeInputVars();
1577     write_stringstream(fGlobals, *rawOut);
1578 
1579     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1580         Layout layout;
1581         switch (fProgram.fKind) {
1582             case Program::kVertex_Kind: {
1583                 Modifiers modifiers(layout, Modifiers::kOut_Flag);
1584                 this->writeModifiers(modifiers, true);
1585                 if (this->usesPrecisionModifiers()) {
1586                     this->write("highp ");
1587                 }
1588                 this->write("vec4 sk_FragCoord_Workaround;\n");
1589                 break;
1590             }
1591             case Program::kFragment_Kind: {
1592                 Modifiers modifiers(layout, Modifiers::kIn_Flag);
1593                 this->writeModifiers(modifiers, true);
1594                 if (this->usesPrecisionModifiers()) {
1595                     this->write("highp ");
1596                 }
1597                 this->write("vec4 sk_FragCoord_Workaround;\n");
1598                 break;
1599             }
1600             default:
1601                 break;
1602         }
1603     }
1604 
1605     if (this->usesPrecisionModifiers()) {
1606         this->writeLine("precision mediump float;");
1607         this->writeLine("precision mediump sampler2D;");
1608         if (fFoundExternalSamplerDecl &&
1609             !fProgram.fSettings.fCaps->noDefaultPrecisionForExternalSamplers()) {
1610             this->writeLine("precision mediump samplerExternalOES;");
1611         }
1612         if (fFoundRectSamplerDecl) {
1613             this->writeLine("precision mediump sampler2DRect;");
1614         }
1615     }
1616     write_stringstream(fExtraFunctions, *rawOut);
1617     write_stringstream(body, *rawOut);
1618     return true;
1619 }
1620 
1621 }
1622