1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkSLGLSLCodeGenerator.h"
9 
10 #include "SkSLCompiler.h"
11 #include "ir/SkSLExpressionStatement.h"
12 #include "ir/SkSLExtension.h"
13 #include "ir/SkSLIndexExpression.h"
14 #include "ir/SkSLModifiersDeclaration.h"
15 #include "ir/SkSLNop.h"
16 #include "ir/SkSLVariableReference.h"
17 
18 #ifndef SKSL_STANDALONE
19 #include "SkOnce.h"
20 #endif
21 
22 namespace SkSL {
23 
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)["texture"]     = FunctionClass::kTexture;
474         (*fFunctionClasses)["transpose"]   = FunctionClass::kTranspose;
475     }
476 #ifndef SKSL_STANDALONE
477     );
478 #endif
479     const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
480                                               fFunctionClasses->end();
481     bool isTextureFunctionWithBias = false;
482     bool nameWritten = false;
483     if (found != fFunctionClasses->end()) {
484         switch (found->second) {
485             case FunctionClass::kAbs: {
486                 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
487                     break;
488                 SkASSERT(c.fArguments.size() == 1);
489                 if (c.fArguments[0]->fType != *fContext.fInt_Type)
490                   break;
491                 // abs(int) on Intel OSX is incorrect, so emulate it:
492                 String name = "_absemulation";
493                 this->write(name);
494                 nameWritten = true;
495                 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
496                     fWrittenIntrinsics.insert(name);
497                     fExtraFunctions.writeText((
498                         "int " + name + "(int x) {\n"
499                         "    return x * sign(x);\n"
500                         "}\n"
501                     ).c_str());
502                 }
503                 break;
504             }
505             case FunctionClass::kAtan:
506                 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
507                     c.fArguments.size() == 2 &&
508                     c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
509                     const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
510                     if (p.fOperator == Token::MINUS) {
511                         this->write("atan(");
512                         this->writeExpression(*c.fArguments[0], kSequence_Precedence);
513                         this->write(", -1.0 * ");
514                         this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
515                         this->write(")");
516                         return;
517                     }
518                 }
519                 break;
520             case FunctionClass::kDFdy:
521                 if (fProgram.fSettings.fFlipY) {
522                     // Flipping Y also negates the Y derivatives.
523                     this->write("-dFdy");
524                     nameWritten = true;
525                 }
526                 // fallthru
527             case FunctionClass::kDFdx:
528             case FunctionClass::kFwidth:
529                 if (!fFoundDerivatives &&
530                     fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
531                     SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
532                     this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
533                     fFoundDerivatives = true;
534                 }
535                 break;
536             case FunctionClass::kDeterminant:
537                 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
538                     SkASSERT(c.fArguments.size() == 1);
539                     this->writeDeterminantHack(*c.fArguments[0]);
540                     return;
541                 }
542                 break;
543             case FunctionClass::kFMA:
544                 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
545                     SkASSERT(c.fArguments.size() == 3);
546                     this->write("((");
547                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
548                     this->write(") * (");
549                     this->writeExpression(*c.fArguments[1], kSequence_Precedence);
550                     this->write(") + (");
551                     this->writeExpression(*c.fArguments[2], kSequence_Precedence);
552                     this->write("))");
553                     return;
554                 }
555                 break;
556             case FunctionClass::kFract:
557                 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
558                     SkASSERT(c.fArguments.size() == 1);
559                     this->write("(0.5 - sign(");
560                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
561                     this->write(") * (0.5 - fract(abs(");
562                     this->writeExpression(*c.fArguments[0], kSequence_Precedence);
563                     this->write("))))");
564                     return;
565                 }
566                 break;
567             case FunctionClass::kInverse:
568                 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
569                     SkASSERT(c.fArguments.size() == 1);
570                     this->writeInverseHack(*c.fArguments[0]);
571                     return;
572                 }
573                 break;
574             case FunctionClass::kInverseSqrt:
575                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
576                     SkASSERT(c.fArguments.size() == 1);
577                     this->writeInverseSqrtHack(*c.fArguments[0]);
578                     return;
579                 }
580                 break;
581             case FunctionClass::kMin:
582                 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
583                     SkASSERT(c.fArguments.size() == 2);
584                     if (is_abs(*c.fArguments[0])) {
585                         this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
586                         return;
587                     }
588                     if (is_abs(*c.fArguments[1])) {
589                         // note that this violates the GLSL left-to-right evaluation semantics.
590                         // I doubt it will ever end up mattering, but it's worth calling out.
591                         this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
592                         return;
593                     }
594                 }
595                 break;
596             case FunctionClass::kPow:
597                 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
598                     break;
599                 }
600                 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
601                 // constant.  It's hard to tell what constitutes "constant" here
602                 // so just replace in all cases.
603 
604                 // Change pow(x, y) into exp2(y * log2(x))
605                 this->write("exp2(");
606                 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
607                 this->write(" * log2(");
608                 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
609                 this->write("))");
610                 return;
611             case FunctionClass::kSaturate:
612                 SkASSERT(c.fArguments.size() == 1);
613                 this->write("clamp(");
614                 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
615                 this->write(", 0.0, 1.0)");
616                 return;
617             case FunctionClass::kTexture: {
618                 const char* dim = "";
619                 bool proj = false;
620                 switch (c.fArguments[0]->fType.dimensions()) {
621                     case SpvDim1D:
622                         dim = "1D";
623                         isTextureFunctionWithBias = true;
624                         if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
625                             proj = false;
626                         } else {
627                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
628                             proj = true;
629                         }
630                         break;
631                     case SpvDim2D:
632                         dim = "2D";
633                         if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
634                             isTextureFunctionWithBias = true;
635                         }
636                         if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
637                             proj = false;
638                         } else {
639                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
640                             proj = true;
641                         }
642                         break;
643                     case SpvDim3D:
644                         dim = "3D";
645                         isTextureFunctionWithBias = true;
646                         if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
647                             proj = false;
648                         } else {
649                             SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
650                             proj = true;
651                         }
652                         break;
653                     case SpvDimCube:
654                         dim = "Cube";
655                         isTextureFunctionWithBias = true;
656                         proj = false;
657                         break;
658                     case SpvDimRect:
659                         dim = "Rect";
660                         proj = false;
661                         break;
662                     case SpvDimBuffer:
663                         SkASSERT(false); // doesn't exist
664                         dim = "Buffer";
665                         proj = false;
666                         break;
667                     case SpvDimSubpassData:
668                         SkASSERT(false); // doesn't exist
669                         dim = "SubpassData";
670                         proj = false;
671                         break;
672                 }
673                 this->write("texture");
674                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
675                     this->write(dim);
676                 }
677                 if (proj) {
678                     this->write("Proj");
679                 }
680                 nameWritten = true;
681                 break;
682             }
683             case FunctionClass::kTranspose:
684                 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
685                     SkASSERT(c.fArguments.size() == 1);
686                     this->writeTransposeHack(*c.fArguments[0]);
687                     return;
688                 }
689                 break;
690         }
691     }
692     if (!nameWritten) {
693         this->write(c.fFunction.fName);
694     }
695     this->write("(");
696     const char* separator = "";
697     for (const auto& arg : c.fArguments) {
698         this->write(separator);
699         separator = ", ";
700         this->writeExpression(*arg, kSequence_Precedence);
701     }
702     if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
703         this->write(", -0.5");
704     }
705     this->write(")");
706 }
707 
708 void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
709     if (c.fArguments.size() == 1 &&
710         (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
711         (c.fType.kind() == Type::kScalar_Kind &&
712          c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
713         // in cases like half(float), they're different types as far as SkSL is concerned but the
714         // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
715         // out the inner expression here.
716         this->writeExpression(*c.fArguments[0], parentPrecedence);
717         return;
718     }
719     this->writeType(c.fType);
720     this->write("(");
721     const char* separator = "";
722     for (const auto& arg : c.fArguments) {
723         this->write(separator);
724         separator = ", ";
725         this->writeExpression(*arg, kSequence_Precedence);
726     }
727     this->write(")");
728 }
729 
730 void GLSLCodeGenerator::writeFragCoord() {
731     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
732         if (!fSetupFragCoordWorkaround) {
733             const char* precision = usesPrecisionModifiers() ? "highp " : "";
734             fFunctionHeader += precision;
735             fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
736             fFunctionHeader += precision;
737             fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
738                 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
739             // Ensure that we get exact .5 values for x and y.
740             fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
741                                "vec2(.5);\n";
742             fSetupFragCoordWorkaround = true;
743         }
744         this->write("sk_FragCoord_Resolved");
745         return;
746     }
747 
748     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
749     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
750     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
751     if (!fProgram.fSettings.fFlipY) {
752         this->write("gl_FragCoord");
753     } else if (const char* extension =
754                                   fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
755         if (!fSetupFragPositionGlobal) {
756             if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
757                 this->writeExtension(extension);
758             }
759             fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
760             fSetupFragPositionGlobal = true;
761         }
762         this->write("gl_FragCoord");
763     } else {
764         if (!fSetupFragPositionLocal) {
765             fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
766             fFunctionHeader += "    vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
767                                " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
768             fSetupFragPositionLocal = true;
769         }
770         this->write("sk_FragCoord");
771     }
772 }
773 
774 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
775     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
776         case SK_FRAGCOLOR_BUILTIN:
777             if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
778                 this->write("sk_FragColor");
779             } else {
780                 this->write("gl_FragColor");
781             }
782             break;
783         case SK_FRAGCOORD_BUILTIN:
784             this->writeFragCoord();
785             break;
786         case SK_WIDTH_BUILTIN:
787             this->write("u_skRTWidth");
788             break;
789         case SK_HEIGHT_BUILTIN:
790             this->write("u_skRTHeight");
791             break;
792         case SK_CLOCKWISE_BUILTIN:
793             this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
794             break;
795         case SK_VERTEXID_BUILTIN:
796             this->write("gl_VertexID");
797             break;
798         case SK_INSTANCEID_BUILTIN:
799             this->write("gl_InstanceID");
800             break;
801         case SK_CLIPDISTANCE_BUILTIN:
802             this->write("gl_ClipDistance");
803             break;
804         case SK_IN_BUILTIN:
805             this->write("gl_in");
806             break;
807         case SK_INVOCATIONID_BUILTIN:
808             this->write("gl_InvocationID");
809             break;
810         case SK_LASTFRAGCOLOR_BUILTIN:
811             this->write(fProgram.fSettings.fCaps->fbFetchColorName());
812             break;
813         default:
814             this->write(ref.fVariable.fName);
815     }
816 }
817 
818 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
819     this->writeExpression(*expr.fBase, kPostfix_Precedence);
820     this->write("[");
821     this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
822     this->write("]");
823 }
824 
825 bool is_sk_position(const FieldAccess& f) {
826     return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
827 }
828 
829 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
830     if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
831         this->writeExpression(*f.fBase, kPostfix_Precedence);
832         this->write(".");
833     }
834     switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
835         case SK_CLIPDISTANCE_BUILTIN:
836             this->write("gl_ClipDistance");
837             break;
838         default:
839             StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
840             if (name == "sk_Position") {
841                 this->write("gl_Position");
842             } else if (name == "sk_PointSize") {
843                 this->write("gl_PointSize");
844             } else {
845                 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
846             }
847     }
848 }
849 
850 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
851     int last = swizzle.fComponents.back();
852     if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
853         this->writeType(swizzle.fType);
854         this->write("(");
855     }
856     this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
857     this->write(".");
858     for (int c : swizzle.fComponents) {
859         if (c >= 0) {
860             this->write(&("x\0y\0z\0w\0"[c * 2]));
861         }
862     }
863     if (last == SKSL_SWIZZLE_0) {
864         this->write(", 0)");
865     }
866     else if (last == SKSL_SWIZZLE_1) {
867         this->write(", 1)");
868     }
869 }
870 
871 GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
872     switch (op) {
873         case Token::STAR:         // fall through
874         case Token::SLASH:        // fall through
875         case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
876         case Token::PLUS:         // fall through
877         case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
878         case Token::SHL:          // fall through
879         case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
880         case Token::LT:           // fall through
881         case Token::GT:           // fall through
882         case Token::LTEQ:         // fall through
883         case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
884         case Token::EQEQ:         // fall through
885         case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
886         case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
887         case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
888         case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
889         case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
890         case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
891         case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
892         case Token::EQ:           // fall through
893         case Token::PLUSEQ:       // fall through
894         case Token::MINUSEQ:      // fall through
895         case Token::STAREQ:       // fall through
896         case Token::SLASHEQ:      // fall through
897         case Token::PERCENTEQ:    // fall through
898         case Token::SHLEQ:        // fall through
899         case Token::SHREQ:        // fall through
900         case Token::LOGICALANDEQ: // fall through
901         case Token::LOGICALXOREQ: // fall through
902         case Token::LOGICALOREQ:  // fall through
903         case Token::BITWISEANDEQ: // fall through
904         case Token::BITWISEXOREQ: // fall through
905         case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
906         case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
907         default: ABORT("unsupported binary operator");
908     }
909 }
910 
911 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
912                                               Precedence parentPrecedence) {
913     if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
914             (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
915         this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
916         return;
917     }
918 
919     Precedence precedence = GetBinaryPrecedence(b.fOperator);
920     if (precedence >= parentPrecedence) {
921         this->write("(");
922     }
923     bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
924                               Compiler::IsAssignment(b.fOperator) &&
925                               Expression::kFieldAccess_Kind == b.fLeft->fKind &&
926                               is_sk_position((FieldAccess&) *b.fLeft) &&
927                               !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
928                               !fProgram.fSettings.fCaps->canUseFragCoord();
929     if (positionWorkaround) {
930         this->write("sk_FragCoord_Workaround = (");
931     }
932     this->writeExpression(*b.fLeft, precedence);
933     this->write(" ");
934     this->write(Compiler::OperatorName(b.fOperator));
935     this->write(" ");
936     this->writeExpression(*b.fRight, precedence);
937     if (positionWorkaround) {
938         this->write(")");
939     }
940     if (precedence >= parentPrecedence) {
941         this->write(")");
942     }
943 }
944 
945 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
946                                                               Precedence parentPrecedence) {
947     if (kTernary_Precedence >= parentPrecedence) {
948         this->write("(");
949     }
950 
951     // Transform:
952     // a && b  =>   a ? b : false
953     // a || b  =>   a ? true : b
954     this->writeExpression(*b.fLeft, kTernary_Precedence);
955     this->write(" ? ");
956     if (b.fOperator == Token::LOGICALAND) {
957         this->writeExpression(*b.fRight, kTernary_Precedence);
958     } else {
959         BoolLiteral boolTrue(fContext, -1, true);
960         this->writeBoolLiteral(boolTrue);
961     }
962     this->write(" : ");
963     if (b.fOperator == Token::LOGICALAND) {
964         BoolLiteral boolFalse(fContext, -1, false);
965         this->writeBoolLiteral(boolFalse);
966     } else {
967         this->writeExpression(*b.fRight, kTernary_Precedence);
968     }
969     if (kTernary_Precedence >= parentPrecedence) {
970         this->write(")");
971     }
972 }
973 
974 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
975                                                Precedence parentPrecedence) {
976     if (kTernary_Precedence >= parentPrecedence) {
977         this->write("(");
978     }
979     this->writeExpression(*t.fTest, kTernary_Precedence);
980     this->write(" ? ");
981     this->writeExpression(*t.fIfTrue, kTernary_Precedence);
982     this->write(" : ");
983     this->writeExpression(*t.fIfFalse, kTernary_Precedence);
984     if (kTernary_Precedence >= parentPrecedence) {
985         this->write(")");
986     }
987 }
988 
989 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
990                                               Precedence parentPrecedence) {
991     if (kPrefix_Precedence >= parentPrecedence) {
992         this->write("(");
993     }
994     this->write(Compiler::OperatorName(p.fOperator));
995     this->writeExpression(*p.fOperand, kPrefix_Precedence);
996     if (kPrefix_Precedence >= parentPrecedence) {
997         this->write(")");
998     }
999 }
1000 
1001 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
1002                                                Precedence parentPrecedence) {
1003     if (kPostfix_Precedence >= parentPrecedence) {
1004         this->write("(");
1005     }
1006     this->writeExpression(*p.fOperand, kPostfix_Precedence);
1007     this->write(Compiler::OperatorName(p.fOperator));
1008     if (kPostfix_Precedence >= parentPrecedence) {
1009         this->write(")");
1010     }
1011 }
1012 
1013 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1014     this->write(b.fValue ? "true" : "false");
1015 }
1016 
1017 void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1018     if (i.fType == *fContext.fUInt_Type) {
1019         this->write(to_string(i.fValue & 0xffffffff) + "u");
1020     } else if (i.fType == *fContext.fUShort_Type) {
1021         this->write(to_string(i.fValue & 0xffff) + "u");
1022     } else if (i.fType == *fContext.fUByte_Type) {
1023         this->write(to_string(i.fValue & 0xff) + "u");
1024     } else {
1025         this->write(to_string((int32_t) i.fValue));
1026     }
1027 }
1028 
1029 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1030     this->write(to_string(f.fValue));
1031 }
1032 
1033 void GLSLCodeGenerator::writeSetting(const Setting& s) {
1034     ABORT("internal error; setting was not folded to a constant during compilation\n");
1035 }
1036 
1037 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1038     if (fProgramKind != Program::kPipelineStage_Kind) {
1039         this->writeTypePrecision(f.fDeclaration.fReturnType);
1040         this->writeType(f.fDeclaration.fReturnType);
1041         this->write(" " + f.fDeclaration.fName + "(");
1042         const char* separator = "";
1043         for (const auto& param : f.fDeclaration.fParameters) {
1044             this->write(separator);
1045             separator = ", ";
1046             this->writeModifiers(param->fModifiers, false);
1047             std::vector<int> sizes;
1048             const Type* type = &param->fType;
1049             while (type->kind() == Type::kArray_Kind) {
1050                 sizes.push_back(type->columns());
1051                 type = &type->componentType();
1052             }
1053             this->writeTypePrecision(*type);
1054             this->writeType(*type);
1055             this->write(" " + param->fName);
1056             for (int s : sizes) {
1057                 if (s <= 0) {
1058                     this->write("[]");
1059                 } else {
1060                     this->write("[" + to_string(s) + "]");
1061                 }
1062             }
1063         }
1064         this->writeLine(") {");
1065         fIndentation++;
1066     }
1067     fFunctionHeader = "";
1068     OutputStream* oldOut = fOut;
1069     StringStream buffer;
1070     fOut = &buffer;
1071     this->writeStatements(((Block&) *f.fBody).fStatements);
1072     if (fProgramKind != Program::kPipelineStage_Kind) {
1073         fIndentation--;
1074         this->writeLine("}");
1075     }
1076 
1077     fOut = oldOut;
1078     this->write(fFunctionHeader);
1079     this->write(buffer.str());
1080 }
1081 
1082 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
1083                                        bool globalContext) {
1084     if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1085         this->write("flat ");
1086     }
1087     if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1088         this->write("noperspective ");
1089     }
1090     String layout = modifiers.fLayout.description();
1091     if (layout.size()) {
1092         this->write(layout + " ");
1093     }
1094     if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1095         this->write("readonly ");
1096     }
1097     if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1098         this->write("writeonly ");
1099     }
1100     if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1101         this->write("coherent ");
1102     }
1103     if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1104         this->write("volatile ");
1105     }
1106     if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1107         this->write("restrict ");
1108     }
1109     if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
1110         (modifiers.fFlags & Modifiers::kOut_Flag)) {
1111         this->write("inout ");
1112     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
1113         if (globalContext &&
1114             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1115             this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1116                                                               : "varying ");
1117         } else {
1118             this->write("in ");
1119         }
1120     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1121         if (globalContext &&
1122             fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1123             this->write("varying ");
1124         } else {
1125             this->write("out ");
1126         }
1127     }
1128     if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1129         this->write("uniform ");
1130     }
1131     if (modifiers.fFlags & Modifiers::kConst_Flag) {
1132         this->write("const ");
1133     }
1134     if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1135         this->write("__pixel_localEXT ");
1136     }
1137     if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1138         this->write("__pixel_local_inEXT ");
1139     }
1140     if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1141         this->write("__pixel_local_outEXT ");
1142     }
1143     switch (modifiers.fLayout.fFormat) {
1144         case Layout::Format::kUnspecified:
1145             break;
1146         case Layout::Format::kRGBA32F: // fall through
1147         case Layout::Format::kR32F:
1148             this->write("highp ");
1149             break;
1150         case Layout::Format::kRGBA16F: // fall through
1151         case Layout::Format::kR16F:    // fall through
1152         case Layout::Format::kRG16F:
1153             this->write("mediump ");
1154             break;
1155         case Layout::Format::kRGBA8:  // fall through
1156         case Layout::Format::kR8:     // fall through
1157         case Layout::Format::kRGBA8I: // fall through
1158         case Layout::Format::kR8I:
1159             this->write("lowp ");
1160             break;
1161     }
1162 }
1163 
1164 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1165     if (intf.fTypeName == "sk_PerVertex") {
1166         return;
1167     }
1168     this->writeModifiers(intf.fVariable.fModifiers, true);
1169     this->writeLine(intf.fTypeName + " {");
1170     fIndentation++;
1171     const Type* structType = &intf.fVariable.fType;
1172     while (structType->kind() == Type::kArray_Kind) {
1173         structType = &structType->componentType();
1174     }
1175     for (const auto& f : structType->fields()) {
1176         this->writeModifiers(f.fModifiers, false);
1177         this->writeTypePrecision(*f.fType);
1178         this->writeType(*f.fType);
1179         this->writeLine(" " + f.fName + ";");
1180     }
1181     fIndentation--;
1182     this->write("}");
1183     if (intf.fInstanceName.size()) {
1184         this->write(" ");
1185         this->write(intf.fInstanceName);
1186         for (const auto& size : intf.fSizes) {
1187             this->write("[");
1188             if (size) {
1189                 this->writeExpression(*size, kTopLevel_Precedence);
1190             }
1191             this->write("]");
1192         }
1193     }
1194     this->writeLine(";");
1195 }
1196 
1197 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1198     this->writeExpression(value, kTopLevel_Precedence);
1199 }
1200 
1201 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1202     if (usesPrecisionModifiers()) {
1203         switch (type.kind()) {
1204             case Type::kScalar_Kind:
1205                 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1206                     type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
1207                     if (fProgram.fSettings.fForceHighPrecision ||
1208                             fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1209                         return "highp ";
1210                     }
1211                     return "mediump ";
1212                 }
1213                 if (type == *fContext.fHalf_Type) {
1214                     return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
1215                 }
1216                 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1217                         type == *fContext.fUInt_Type) {
1218                     return "highp ";
1219                 }
1220                 return "";
1221             case Type::kVector_Kind: // fall through
1222             case Type::kMatrix_Kind:
1223                 return this->getTypePrecision(type.componentType());
1224             default:
1225                 break;
1226         }
1227     }
1228     return "";
1229 }
1230 
1231 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1232     this->write(this->getTypePrecision(type));
1233 }
1234 
1235 void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
1236     if (!decl.fVars.size()) {
1237         return;
1238     }
1239     bool wroteType = false;
1240     for (const auto& stmt : decl.fVars) {
1241         VarDeclaration& var = (VarDeclaration&) *stmt;
1242         if (wroteType) {
1243             this->write(", ");
1244         } else {
1245             this->writeModifiers(var.fVar->fModifiers, global);
1246             this->writeTypePrecision(decl.fBaseType);
1247             this->writeType(decl.fBaseType);
1248             this->write(" ");
1249             wroteType = true;
1250         }
1251         this->write(var.fVar->fName);
1252         for (const auto& size : var.fSizes) {
1253             this->write("[");
1254             if (size) {
1255                 this->writeExpression(*size, kTopLevel_Precedence);
1256             }
1257             this->write("]");
1258         }
1259         if (var.fValue) {
1260             this->write(" = ");
1261             this->writeVarInitializer(*var.fVar, *var.fValue);
1262         }
1263         if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
1264             if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
1265                 this->writeExtension(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
1266             }
1267             fFoundImageDecl = true;
1268         }
1269         if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1270             if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
1271                 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
1272             }
1273             if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
1274                 this->writeExtension(
1275                                   fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
1276             }
1277             fFoundExternalSamplerDecl = true;
1278         }
1279     }
1280     if (wroteType) {
1281         this->write(";");
1282     }
1283 }
1284 
1285 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1286     switch (s.fKind) {
1287         case Statement::kBlock_Kind:
1288             this->writeBlock((Block&) s);
1289             break;
1290         case Statement::kExpression_Kind:
1291             this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1292             this->write(";");
1293             break;
1294         case Statement::kReturn_Kind:
1295             this->writeReturnStatement((ReturnStatement&) s);
1296             break;
1297         case Statement::kVarDeclarations_Kind:
1298             this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
1299             break;
1300         case Statement::kIf_Kind:
1301             this->writeIfStatement((IfStatement&) s);
1302             break;
1303         case Statement::kFor_Kind:
1304             this->writeForStatement((ForStatement&) s);
1305             break;
1306         case Statement::kWhile_Kind:
1307             this->writeWhileStatement((WhileStatement&) s);
1308             break;
1309         case Statement::kDo_Kind:
1310             this->writeDoStatement((DoStatement&) s);
1311             break;
1312         case Statement::kSwitch_Kind:
1313             this->writeSwitchStatement((SwitchStatement&) s);
1314             break;
1315         case Statement::kBreak_Kind:
1316             this->write("break;");
1317             break;
1318         case Statement::kContinue_Kind:
1319             this->write("continue;");
1320             break;
1321         case Statement::kDiscard_Kind:
1322             this->write("discard;");
1323             break;
1324         case Statement::kNop_Kind:
1325             this->write(";");
1326             break;
1327         default:
1328             ABORT("unsupported statement: %s", s.description().c_str());
1329     }
1330 }
1331 
1332 void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1333     for (const auto& s : statements) {
1334         if (!s->isEmpty()) {
1335             this->writeStatement(*s);
1336             this->writeLine();
1337         }
1338     }
1339 }
1340 
1341 void GLSLCodeGenerator::writeBlock(const Block& b) {
1342     this->writeLine("{");
1343     fIndentation++;
1344     this->writeStatements(b.fStatements);
1345     fIndentation--;
1346     this->write("}");
1347 }
1348 
1349 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1350     this->write("if (");
1351     this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1352     this->write(") ");
1353     this->writeStatement(*stmt.fIfTrue);
1354     if (stmt.fIfFalse) {
1355         this->write(" else ");
1356         this->writeStatement(*stmt.fIfFalse);
1357     }
1358 }
1359 
1360 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1361     this->write("for (");
1362     if (f.fInitializer && !f.fInitializer->isEmpty()) {
1363         this->writeStatement(*f.fInitializer);
1364     } else {
1365         this->write("; ");
1366     }
1367     if (f.fTest) {
1368         if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1369             std::unique_ptr<Expression> and_true(new BinaryExpression(
1370                     -1, f.fTest->clone(), Token::LOGICALAND,
1371                     std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1372                                                                  true)),
1373                     *fContext.fBool_Type));
1374             this->writeExpression(*and_true, kTopLevel_Precedence);
1375         } else {
1376             this->writeExpression(*f.fTest, kTopLevel_Precedence);
1377         }
1378     }
1379     this->write("; ");
1380     if (f.fNext) {
1381         this->writeExpression(*f.fNext, kTopLevel_Precedence);
1382     }
1383     this->write(") ");
1384     this->writeStatement(*f.fStatement);
1385 }
1386 
1387 void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1388     this->write("while (");
1389     this->writeExpression(*w.fTest, kTopLevel_Precedence);
1390     this->write(") ");
1391     this->writeStatement(*w.fStatement);
1392 }
1393 
1394 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1395     if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1396         this->write("do ");
1397         this->writeStatement(*d.fStatement);
1398         this->write(" while (");
1399         this->writeExpression(*d.fTest, kTopLevel_Precedence);
1400         this->write(");");
1401         return;
1402     }
1403 
1404     // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1405     //     do {
1406     //         CODE;
1407     //     } while (CONDITION)
1408     //
1409     // to loops of the form
1410     //     bool temp = false;
1411     //     while (true) {
1412     //         if (temp) {
1413     //             if (!CONDITION) {
1414     //                 break;
1415     //             }
1416     //         }
1417     //         temp = true;
1418     //         CODE;
1419     //     }
1420     String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1421     this->write("bool ");
1422     this->write(tmpVar);
1423     this->writeLine(" = false;");
1424     this->writeLine("while (true) {");
1425     fIndentation++;
1426     this->write("if (");
1427     this->write(tmpVar);
1428     this->writeLine(") {");
1429     fIndentation++;
1430     this->write("if (!");
1431     this->writeExpression(*d.fTest, kPrefix_Precedence);
1432     this->writeLine(") {");
1433     fIndentation++;
1434     this->writeLine("break;");
1435     fIndentation--;
1436     this->writeLine("}");
1437     fIndentation--;
1438     this->writeLine("}");
1439     this->write(tmpVar);
1440     this->writeLine(" = true;");
1441     this->writeStatement(*d.fStatement);
1442     this->writeLine();
1443     fIndentation--;
1444     this->write("}");
1445 }
1446 
1447 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1448     this->write("switch (");
1449     this->writeExpression(*s.fValue, kTopLevel_Precedence);
1450     this->writeLine(") {");
1451     fIndentation++;
1452     for (const auto& c : s.fCases) {
1453         if (c->fValue) {
1454             this->write("case ");
1455             this->writeExpression(*c->fValue, kTopLevel_Precedence);
1456             this->writeLine(":");
1457         } else {
1458             this->writeLine("default:");
1459         }
1460         fIndentation++;
1461         for (const auto& stmt : c->fStatements) {
1462             this->writeStatement(*stmt);
1463             this->writeLine();
1464         }
1465         fIndentation--;
1466     }
1467     fIndentation--;
1468     this->write("}");
1469 }
1470 
1471 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1472     this->write("return");
1473     if (r.fExpression) {
1474         this->write(" ");
1475         this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1476     }
1477     this->write(";");
1478 }
1479 
1480 void GLSLCodeGenerator::writeHeader() {
1481     this->write(fProgram.fSettings.fCaps->versionDeclString());
1482     this->writeLine();
1483 }
1484 
1485 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1486     switch (e.fKind) {
1487         case ProgramElement::kExtension_Kind:
1488             this->writeExtension(((Extension&) e).fName);
1489             break;
1490         case ProgramElement::kVar_Kind: {
1491             VarDeclarations& decl = (VarDeclarations&) e;
1492             if (decl.fVars.size() > 0) {
1493                 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
1494                 if (builtin == -1) {
1495                     // normal var
1496                     this->writeVarDeclarations(decl, true);
1497                     this->writeLine();
1498                 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1499                            fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
1500                            ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
1501                     if (fProgram.fSettings.fFragColorIsInOut) {
1502                         this->write("inout ");
1503                     } else {
1504                         this->write("out ");
1505                     }
1506                     if (usesPrecisionModifiers()) {
1507                         this->write("mediump ");
1508                     }
1509                     this->writeLine("vec4 sk_FragColor;");
1510                 }
1511             }
1512             break;
1513         }
1514         case ProgramElement::kInterfaceBlock_Kind:
1515             this->writeInterfaceBlock((InterfaceBlock&) e);
1516             break;
1517         case ProgramElement::kFunction_Kind:
1518             this->writeFunction((FunctionDefinition&) e);
1519             break;
1520         case ProgramElement::kModifiers_Kind: {
1521             const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1522             if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1523                 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
1524                     this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
1525                 }
1526                 fFoundGSInvocations = true;
1527             }
1528             this->writeModifiers(modifiers, true);
1529             this->writeLine(";");
1530             break;
1531         }
1532         case ProgramElement::kEnum_Kind:
1533             break;
1534         default:
1535             printf("%s\n", e.description().c_str());
1536             ABORT("unsupported program element");
1537     }
1538 }
1539 
1540 void GLSLCodeGenerator::writeInputVars() {
1541     if (fProgram.fInputs.fRTWidth) {
1542         const char* precision = usesPrecisionModifiers() ? "highp " : "";
1543         fGlobals.writeText("uniform ");
1544         fGlobals.writeText(precision);
1545         fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1546     }
1547     if (fProgram.fInputs.fRTHeight) {
1548         const char* precision = usesPrecisionModifiers() ? "highp " : "";
1549         fGlobals.writeText("uniform ");
1550         fGlobals.writeText(precision);
1551         fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1552     }
1553 }
1554 
1555 bool GLSLCodeGenerator::generateCode() {
1556     if (fProgramKind != Program::kPipelineStage_Kind) {
1557         this->writeHeader();
1558     }
1559     if (Program::kGeometry_Kind == fProgramKind &&
1560         fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
1561         this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
1562     }
1563     OutputStream* rawOut = fOut;
1564     StringStream body;
1565     fOut = &body;
1566     for (const auto& e : fProgram) {
1567         this->writeProgramElement(e);
1568     }
1569     fOut = rawOut;
1570 
1571     write_stringstream(fExtensions, *rawOut);
1572     this->writeInputVars();
1573     write_stringstream(fGlobals, *rawOut);
1574 
1575     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1576         Layout layout;
1577         switch (fProgram.fKind) {
1578             case Program::kVertex_Kind: {
1579                 Modifiers modifiers(layout, Modifiers::kOut_Flag);
1580                 this->writeModifiers(modifiers, true);
1581                 if (this->usesPrecisionModifiers()) {
1582                     this->write("highp ");
1583                 }
1584                 this->write("vec4 sk_FragCoord_Workaround;\n");
1585                 break;
1586             }
1587             case Program::kFragment_Kind: {
1588                 Modifiers modifiers(layout, Modifiers::kIn_Flag);
1589                 this->writeModifiers(modifiers, true);
1590                 if (this->usesPrecisionModifiers()) {
1591                     this->write("highp ");
1592                 }
1593                 this->write("vec4 sk_FragCoord_Workaround;\n");
1594                 break;
1595             }
1596             default:
1597                 break;
1598         }
1599     }
1600 
1601     if (this->usesPrecisionModifiers()) {
1602         this->writeLine("precision mediump float;");
1603     }
1604     write_stringstream(fExtraFunctions, *rawOut);
1605     write_stringstream(body, *rawOut);
1606     return true;
1607 }
1608 
1609 }
1610