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/codegen/SkSLGLSLCodeGenerator.h"
9 
10 #include <memory>
11 
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/ir/SkSLExpressionStatement.h"
14 #include "src/sksl/ir/SkSLExtension.h"
15 #include "src/sksl/ir/SkSLIndexExpression.h"
16 #include "src/sksl/ir/SkSLModifiersDeclaration.h"
17 #include "src/sksl/ir/SkSLNop.h"
18 #include "src/sksl/ir/SkSLStructDefinition.h"
19 #include "src/sksl/ir/SkSLVariableReference.h"
20 
21 #ifndef SKSL_STANDALONE
22 #include "include/private/SkOnce.h"
23 #endif
24 
25 namespace SkSL {
26 
write(const char * s)27 void GLSLCodeGenerator::write(const char* s) {
28     if (s[0] == 0) {
29         return;
30     }
31     if (fAtLineStart) {
32         for (int i = 0; i < fIndentation; i++) {
33             fOut->writeText("    ");
34         }
35     }
36     fOut->writeText(s);
37     fAtLineStart = false;
38 }
39 
writeLine(const char * s)40 void GLSLCodeGenerator::writeLine(const char* s) {
41     this->write(s);
42     this->writeLine();
43 }
44 
write(const String & s)45 void GLSLCodeGenerator::write(const String& s) {
46     this->write(s.c_str());
47 }
48 
write(StringFragment s)49 void GLSLCodeGenerator::write(StringFragment s) {
50     if (!s.fLength) {
51         return;
52     }
53     if (fAtLineStart) {
54         for (int i = 0; i < fIndentation; i++) {
55             fOut->writeText("    ");
56         }
57     }
58     fOut->write(s.fChars, s.fLength);
59     fAtLineStart = false;
60 }
61 
writeLine(const String & s)62 void GLSLCodeGenerator::writeLine(const String& s) {
63     this->writeLine(s.c_str());
64 }
65 
writeLine()66 void GLSLCodeGenerator::writeLine() {
67     fOut->writeText(fLineEnding);
68     fAtLineStart = true;
69 }
70 
finishLine()71 void GLSLCodeGenerator::finishLine() {
72     if (!fAtLineStart) {
73         this->writeLine();
74     }
75 }
76 
writeExtension(const String & name)77 void GLSLCodeGenerator::writeExtension(const String& name) {
78     this->writeExtension(name, true);
79 }
80 
writeExtension(const String & name,bool require)81 void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
82     fExtensions.writeText("#extension ");
83     fExtensions.write(name.c_str(), name.length());
84     fExtensions.writeText(require ? " : require\n" : " : enable\n");
85 }
86 
usesPrecisionModifiers() const87 bool GLSLCodeGenerator::usesPrecisionModifiers() const {
88     return this->caps().usesPrecisionModifiers();
89 }
90 
91 // Returns the name of the type with array dimensions, e.g. `float[2]`.
getTypeName(const Type & type)92 String GLSLCodeGenerator::getTypeName(const Type& type) {
93     switch (type.typeKind()) {
94         case Type::TypeKind::kVector: {
95             const Type& component = type.componentType();
96             String result;
97             if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
98                 result = "vec";
99             }
100             else if (component.isSigned()) {
101                 result = "ivec";
102             }
103             else if (component.isUnsigned()) {
104                 result = "uvec";
105             }
106             else if (component == *fContext.fTypes.fBool) {
107                 result = "bvec";
108             }
109             else {
110                 SK_ABORT("unsupported vector type");
111             }
112             result += to_string(type.columns());
113             return result;
114         }
115         case Type::TypeKind::kMatrix: {
116             String result;
117             const Type& component = type.componentType();
118             if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
119                 result = "mat";
120             }
121             else {
122                 SK_ABORT("unsupported matrix type");
123             }
124             result += to_string(type.columns());
125             if (type.columns() != type.rows()) {
126                 result += "x";
127                 result += to_string(type.rows());
128             }
129             return result;
130         }
131         case Type::TypeKind::kArray: {
132             String baseTypeName = this->getTypeName(type.componentType());
133             return (type.columns() == Type::kUnsizedArray)
134                            ? String::printf("%s[]", baseTypeName.c_str())
135                            : String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
136         }
137         case Type::TypeKind::kScalar: {
138             if (type == *fContext.fTypes.fHalf) {
139                 return "float";
140             }
141             else if (type == *fContext.fTypes.fShort) {
142                 return "int";
143             }
144             else if (type == *fContext.fTypes.fUShort) {
145                 return "uint";
146             }
147             else {
148                 return type.name();
149             }
150             break;
151         }
152         case Type::TypeKind::kEnum:
153             return "int";
154         default:
155             return type.name();
156     }
157 }
158 
writeStructDefinition(const StructDefinition & s)159 void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) {
160     const Type& type = s.type();
161     this->write("struct ");
162     this->write(type.name());
163     this->writeLine(" {");
164     fIndentation++;
165     for (const auto& f : type.fields()) {
166         this->writeModifiers(f.fModifiers, false);
167         this->writeTypePrecision(*f.fType);
168         const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
169         this->writeType(baseType);
170         this->write(" ");
171         this->write(f.fName);
172         if (f.fType->isArray()) {
173             this->write("[" + to_string(f.fType->columns()) + "]");
174         }
175         this->writeLine(";");
176     }
177     fIndentation--;
178     this->writeLine("};");
179 }
180 
writeType(const Type & type)181 void GLSLCodeGenerator::writeType(const Type& type) {
182     this->write(this->getTypeName(type));
183 }
184 
writeExpression(const Expression & expr,Precedence parentPrecedence)185 void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
186     switch (expr.kind()) {
187         case Expression::Kind::kBinary:
188             this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
189             break;
190         case Expression::Kind::kBoolLiteral:
191             this->writeBoolLiteral(expr.as<BoolLiteral>());
192             break;
193         case Expression::Kind::kConstructorArray:
194         case Expression::Kind::kConstructorCompound:
195         case Expression::Kind::kConstructorDiagonalMatrix:
196         case Expression::Kind::kConstructorMatrixResize:
197         case Expression::Kind::kConstructorSplat:
198         case Expression::Kind::kConstructorStruct:
199             this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
200             break;
201         case Expression::Kind::kConstructorScalarCast:
202         case Expression::Kind::kConstructorCompoundCast:
203             this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
204             break;
205         case Expression::Kind::kIntLiteral:
206             this->writeIntLiteral(expr.as<IntLiteral>());
207             break;
208         case Expression::Kind::kFieldAccess:
209             this->writeFieldAccess(expr.as<FieldAccess>());
210             break;
211         case Expression::Kind::kFloatLiteral:
212             this->writeFloatLiteral(expr.as<FloatLiteral>());
213             break;
214         case Expression::Kind::kFunctionCall:
215             this->writeFunctionCall(expr.as<FunctionCall>());
216             break;
217         case Expression::Kind::kPrefix:
218             this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
219             break;
220         case Expression::Kind::kPostfix:
221             this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
222             break;
223         case Expression::Kind::kSetting:
224             this->writeSetting(expr.as<Setting>());
225             break;
226         case Expression::Kind::kSwizzle:
227             this->writeSwizzle(expr.as<Swizzle>());
228             break;
229         case Expression::Kind::kVariableReference:
230             this->writeVariableReference(expr.as<VariableReference>());
231             break;
232         case Expression::Kind::kTernary:
233             this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
234             break;
235         case Expression::Kind::kIndex:
236             this->writeIndexExpression(expr.as<IndexExpression>());
237             break;
238         default:
239             SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
240             break;
241     }
242 }
243 
is_abs(Expression & expr)244 static bool is_abs(Expression& expr) {
245     if (expr.kind() != Expression::Kind::kFunctionCall) {
246         return false;
247     }
248     return expr.as<FunctionCall>().function().name() == "abs";
249 }
250 
251 // turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
252 // Tegra3 compiler bug.
writeMinAbsHack(Expression & absExpr,Expression & otherExpr)253 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
254     SkASSERT(!this->caps().canUseMinAndAbsTogether());
255     String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
256     String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
257     this->fFunctionHeader += String("    ") + this->getTypePrecision(absExpr.type()) +
258                              this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
259     this->fFunctionHeader += String("    ") + this->getTypePrecision(otherExpr.type()) +
260                              this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
261     this->write("((" + tmpVar1 + " = ");
262     this->writeExpression(absExpr, Precedence::kTopLevel);
263     this->write(") < (" + tmpVar2 + " = ");
264     this->writeExpression(otherExpr, Precedence::kAssignment);
265     this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
266 }
267 
writeInverseSqrtHack(const Expression & x)268 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
269     this->write("(1.0 / sqrt(");
270     this->writeExpression(x, Precedence::kTopLevel);
271     this->write("))");
272 }
273 
writeDeterminantHack(const Expression & mat)274 void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
275     String name;
276     const Type& type = mat.type();
277     if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
278         name = "_determinant2";
279         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
280             fWrittenIntrinsics.insert(name);
281             fExtraFunctions.writeText((
282                 "float " + name + "(mat2 m) {"
283                 "    return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
284                 "}"
285             ).c_str());
286         }
287     }
288     else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
289         name = "_determinant3";
290         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
291             fWrittenIntrinsics.insert(name);
292             fExtraFunctions.writeText((
293                 "float " + name + "(mat3 m) {"
294                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
295                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
296                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
297                 "    float b01 = a22 * a11 - a12 * a21;"
298                 "    float b11 = -a22 * a10 + a12 * a20;"
299                 "    float b21 = a21 * a10 - a11 * a20;"
300                 "    return a00 * b01 + a01 * b11 + a02 * b21;"
301                 "}"
302             ).c_str());
303         }
304     }
305     else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
306         name = "_determinant4";
307         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
308             fWrittenIntrinsics.insert(name);
309             fExtraFunctions.writeText((
310                 "mat4 " + name + "(mat4 m) {"
311                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
312                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
313                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
314                 "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
315                 "    float b00 = a00 * a11 - a01 * a10;"
316                 "    float b01 = a00 * a12 - a02 * a10;"
317                 "    float b02 = a00 * a13 - a03 * a10;"
318                 "    float b03 = a01 * a12 - a02 * a11;"
319                 "    float b04 = a01 * a13 - a03 * a11;"
320                 "    float b05 = a02 * a13 - a03 * a12;"
321                 "    float b06 = a20 * a31 - a21 * a30;"
322                 "    float b07 = a20 * a32 - a22 * a30;"
323                 "    float b08 = a20 * a33 - a23 * a30;"
324                 "    float b09 = a21 * a32 - a22 * a31;"
325                 "    float b10 = a21 * a33 - a23 * a31;"
326                 "    float b11 = a22 * a33 - a23 * a32;"
327                 "    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
328                 "}"
329             ).c_str());
330         }
331     }
332     else {
333         SkASSERT(false);
334     }
335     this->write(name + "(");
336     this->writeExpression(mat, Precedence::kTopLevel);
337     this->write(")");
338 }
339 
writeInverseHack(const Expression & mat)340 void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
341     String name;
342     const Type& type = mat.type();
343     if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
344         name = "_inverse2";
345         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
346             fWrittenIntrinsics.insert(name);
347             fExtraFunctions.writeText((
348                 "mat2 " + name + "(mat2 m) {"
349                 "    return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
350                                "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
351                 "}"
352             ).c_str());
353         }
354     }
355     else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
356         name = "_inverse3";
357         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
358             fWrittenIntrinsics.insert(name);
359             fExtraFunctions.writeText((
360                 "mat3 " +  name + "(mat3 m) {"
361                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
362                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
363                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
364                 "    float b01 = a22 * a11 - a12 * a21;"
365                 "    float b11 = -a22 * a10 + a12 * a20;"
366                 "    float b21 = a21 * a10 - a11 * a20;"
367                 "    float det = a00 * b01 + a01 * b11 + a02 * b21;"
368                 "    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
369                 "                b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
370                 "                b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
371                 "}"
372             ).c_str());
373         }
374     }
375     else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
376         name = "_inverse4";
377         if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
378             fWrittenIntrinsics.insert(name);
379             fExtraFunctions.writeText((
380                 "mat4 " + name + "(mat4 m) {"
381                 "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
382                 "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
383                 "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
384                 "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
385                 "    float b00 = a00 * a11 - a01 * a10;"
386                 "    float b01 = a00 * a12 - a02 * a10;"
387                 "    float b02 = a00 * a13 - a03 * a10;"
388                 "    float b03 = a01 * a12 - a02 * a11;"
389                 "    float b04 = a01 * a13 - a03 * a11;"
390                 "    float b05 = a02 * a13 - a03 * a12;"
391                 "    float b06 = a20 * a31 - a21 * a30;"
392                 "    float b07 = a20 * a32 - a22 * a30;"
393                 "    float b08 = a20 * a33 - a23 * a30;"
394                 "    float b09 = a21 * a32 - a22 * a31;"
395                 "    float b10 = a21 * a33 - a23 * a31;"
396                 "    float b11 = a22 * a33 - a23 * a32;"
397                 "    float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
398                 "                b04 * b07 + b05 * b06;"
399                 "    return mat4("
400                 "        a11 * b11 - a12 * b10 + a13 * b09,"
401                 "        a02 * b10 - a01 * b11 - a03 * b09,"
402                 "        a31 * b05 - a32 * b04 + a33 * b03,"
403                 "        a22 * b04 - a21 * b05 - a23 * b03,"
404                 "        a12 * b08 - a10 * b11 - a13 * b07,"
405                 "        a00 * b11 - a02 * b08 + a03 * b07,"
406                 "        a32 * b02 - a30 * b05 - a33 * b01,"
407                 "        a20 * b05 - a22 * b02 + a23 * b01,"
408                 "        a10 * b10 - a11 * b08 + a13 * b06,"
409                 "        a01 * b08 - a00 * b10 - a03 * b06,"
410                 "        a30 * b04 - a31 * b02 + a33 * b00,"
411                 "        a21 * b02 - a20 * b04 - a23 * b00,"
412                 "        a11 * b07 - a10 * b09 - a12 * b06,"
413                 "        a00 * b09 - a01 * b07 + a02 * b06,"
414                 "        a31 * b01 - a30 * b03 - a32 * b00,"
415                 "        a20 * b03 - a21 * b01 + a22 * b00) / det;"
416                 "}"
417             ).c_str());
418         }
419     }
420     else {
421         SkASSERT(false);
422     }
423     this->write(name + "(");
424     this->writeExpression(mat, Precedence::kTopLevel);
425     this->write(")");
426 }
427 
writeTransposeHack(const Expression & mat)428 void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
429     const Type& type = mat.type();
430     String name = "transpose" + to_string(type.columns()) + to_string(type.rows());
431     if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
432         fWrittenIntrinsics.insert(name);
433         String typeName = this->getTypeName(type);
434         const Type& base = type.componentType();
435         String transposed =  this->getTypeName(base.toCompound(fContext,
436                                                                type.rows(),
437                                                                type.columns()));
438         fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " +
439                                   transposed + "(").c_str());
440         const char* separator = "";
441         for (int row = 0; row < type.rows(); ++row) {
442             for (int column = 0; column < type.columns(); ++column) {
443                 fExtraFunctions.writeText(separator);
444                 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
445                                            "]").c_str());
446                 separator = ", ";
447             }
448         }
449         fExtraFunctions.writeText("); }");
450     }
451     this->write(name + "(");
452     this->writeExpression(mat, Precedence::kTopLevel);
453     this->write(")");
454 }
455 
writeFunctionCall(const FunctionCall & c)456 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
457     const FunctionDeclaration& function = c.function();
458     const ExpressionArray& arguments = c.arguments();
459     bool isTextureFunctionWithBias = false;
460     bool nameWritten = false;
461     switch (c.function().intrinsicKind()) {
462         case k_abs_IntrinsicKind: {
463             if (!this->caps().emulateAbsIntFunction())
464                 break;
465             SkASSERT(arguments.size() == 1);
466             if (arguments[0]->type() != *fContext.fTypes.fInt) {
467                 break;
468             }
469             // abs(int) on Intel OSX is incorrect, so emulate it:
470             String name = "_absemulation";
471             this->write(name);
472             nameWritten = true;
473             if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
474                 fWrittenIntrinsics.insert(name);
475                 fExtraFunctions.writeText((
476                     "int " + name + "(int x) {\n"
477                     "    return x * sign(x);\n"
478                     "}\n"
479                 ).c_str());
480             }
481             break;
482         }
483         case k_atan_IntrinsicKind:
484             if (this->caps().mustForceNegatedAtanParamToFloat() &&
485                 arguments.size() == 2 &&
486                 arguments[1]->kind() == Expression::Kind::kPrefix) {
487                 const PrefixExpression& p = (PrefixExpression&) *arguments[1];
488                 if (p.getOperator().kind() == Token::Kind::TK_MINUS) {
489                     this->write("atan(");
490                     this->writeExpression(*arguments[0], Precedence::kSequence);
491                     this->write(", -1.0 * ");
492                     this->writeExpression(*p.operand(), Precedence::kMultiplicative);
493                     this->write(")");
494                     return;
495                 }
496             }
497             break;
498         case k_dFdy_IntrinsicKind:
499             if (fProgram.fConfig->fSettings.fFlipY) {
500                 // Flipping Y also negates the Y derivatives.
501                 this->write("-dFdy");
502                 nameWritten = true;
503             }
504             [[fallthrough]];
505         case k_dFdx_IntrinsicKind:
506         case k_fwidth_IntrinsicKind:
507             if (!fFoundDerivatives &&
508                 this->caps().shaderDerivativeExtensionString()) {
509                 this->writeExtension(this->caps().shaderDerivativeExtensionString());
510                 fFoundDerivatives = true;
511             }
512             break;
513         case k_determinant_IntrinsicKind:
514             if (!this->caps().builtinDeterminantSupport()) {
515                 SkASSERT(arguments.size() == 1);
516                 this->writeDeterminantHack(*arguments[0]);
517                 return;
518             }
519             break;
520         case k_fma_IntrinsicKind:
521             if (!this->caps().builtinFMASupport()) {
522                 SkASSERT(arguments.size() == 3);
523                 this->write("((");
524                 this->writeExpression(*arguments[0], Precedence::kSequence);
525                 this->write(") * (");
526                 this->writeExpression(*arguments[1], Precedence::kSequence);
527                 this->write(") + (");
528                 this->writeExpression(*arguments[2], Precedence::kSequence);
529                 this->write("))");
530                 return;
531             }
532             break;
533         case k_fract_IntrinsicKind:
534             if (!this->caps().canUseFractForNegativeValues()) {
535                 SkASSERT(arguments.size() == 1);
536                 this->write("(0.5 - sign(");
537                 this->writeExpression(*arguments[0], Precedence::kSequence);
538                 this->write(") * (0.5 - fract(abs(");
539                 this->writeExpression(*arguments[0], Precedence::kSequence);
540                 this->write("))))");
541                 return;
542             }
543             break;
544         case k_inverse_IntrinsicKind:
545             if (this->caps().generation() < k140_GrGLSLGeneration) {
546                 SkASSERT(arguments.size() == 1);
547                 this->writeInverseHack(*arguments[0]);
548                 return;
549             }
550             break;
551         case k_inversesqrt_IntrinsicKind:
552             if (this->caps().generation() < k130_GrGLSLGeneration) {
553                 SkASSERT(arguments.size() == 1);
554                 this->writeInverseSqrtHack(*arguments[0]);
555                 return;
556             }
557             break;
558         case k_min_IntrinsicKind:
559             if (!this->caps().canUseMinAndAbsTogether()) {
560                 SkASSERT(arguments.size() == 2);
561                 if (is_abs(*arguments[0])) {
562                     this->writeMinAbsHack(*arguments[0], *arguments[1]);
563                     return;
564                 }
565                 if (is_abs(*arguments[1])) {
566                     // note that this violates the GLSL left-to-right evaluation semantics.
567                     // I doubt it will ever end up mattering, but it's worth calling out.
568                     this->writeMinAbsHack(*arguments[1], *arguments[0]);
569                     return;
570                 }
571             }
572             break;
573         case k_pow_IntrinsicKind:
574             if (!this->caps().removePowWithConstantExponent()) {
575                 break;
576             }
577             // pow(x, y) on some NVIDIA drivers causes crashes if y is a
578             // constant.  It's hard to tell what constitutes "constant" here
579             // so just replace in all cases.
580 
581             // Change pow(x, y) into exp2(y * log2(x))
582             this->write("exp2(");
583             this->writeExpression(*arguments[1], Precedence::kMultiplicative);
584             this->write(" * log2(");
585             this->writeExpression(*arguments[0], Precedence::kSequence);
586             this->write("))");
587             return;
588         case k_saturate_IntrinsicKind:
589             SkASSERT(arguments.size() == 1);
590             this->write("clamp(");
591             this->writeExpression(*arguments[0], Precedence::kSequence);
592             this->write(", 0.0, 1.0)");
593             return;
594         case k_sample_IntrinsicKind: {
595             const char* dim = "";
596             bool proj = false;
597             const Type& arg0Type = arguments[0]->type();
598             const Type& arg1Type = arguments[1]->type();
599             switch (arg0Type.dimensions()) {
600                 case SpvDim1D:
601                     dim = "1D";
602                     isTextureFunctionWithBias = true;
603                     if (arg1Type == *fContext.fTypes.fFloat) {
604                         proj = false;
605                     } else {
606                         SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
607                         proj = true;
608                     }
609                     break;
610                 case SpvDim2D:
611                     dim = "2D";
612                     if (arg0Type != *fContext.fTypes.fSamplerExternalOES) {
613                         isTextureFunctionWithBias = true;
614                     }
615                     if (arg1Type == *fContext.fTypes.fFloat2) {
616                         proj = false;
617                     } else {
618                         SkASSERT(arg1Type == *fContext.fTypes.fFloat3);
619                         proj = true;
620                     }
621                     break;
622                 case SpvDim3D:
623                     dim = "3D";
624                     isTextureFunctionWithBias = true;
625                     if (arg1Type == *fContext.fTypes.fFloat3) {
626                         proj = false;
627                     } else {
628                         SkASSERT(arg1Type == *fContext.fTypes.fFloat4);
629                         proj = true;
630                     }
631                     break;
632                 case SpvDimCube:
633                     dim = "Cube";
634                     isTextureFunctionWithBias = true;
635                     proj = false;
636                     break;
637                 case SpvDimRect:
638                     dim = "2DRect";
639                     proj = false;
640                     break;
641                 case SpvDimBuffer:
642                     SkASSERT(false); // doesn't exist
643                     dim = "Buffer";
644                     proj = false;
645                     break;
646                 case SpvDimSubpassData:
647                     SkASSERT(false); // doesn't exist
648                     dim = "SubpassData";
649                     proj = false;
650                     break;
651             }
652             if (!fTextureFunctionOverride.empty()) {
653                 this->write(fTextureFunctionOverride.c_str());
654             } else {
655                 this->write("texture");
656                 if (this->caps().generation() < k130_GrGLSLGeneration) {
657                     this->write(dim);
658                 }
659                 if (proj) {
660                     this->write("Proj");
661                 }
662             }
663             nameWritten = true;
664             break;
665         }
666         case k_transpose_IntrinsicKind:
667             if (this->caps().generation() < k130_GrGLSLGeneration) {
668                 SkASSERT(arguments.size() == 1);
669                 this->writeTransposeHack(*arguments[0]);
670                 return;
671             }
672             break;
673         default:
674             break;
675     }
676 
677     if (!nameWritten) {
678         this->write(function.mangledName());
679     }
680     this->write("(");
681     const char* separator = "";
682     for (const auto& arg : arguments) {
683         this->write(separator);
684         separator = ", ";
685         this->writeExpression(*arg, Precedence::kSequence);
686     }
687     if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
688         this->write(", -0.5");
689     }
690     this->write(")");
691 }
692 
writeCastConstructor(const AnyConstructor & c,Precedence parentPrecedence)693 void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
694     const auto arguments = c.argumentSpan();
695     SkASSERT(arguments.size() == 1);
696 
697     const Expression& argument = *arguments.front();
698     if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
699          (argument.type() == *fContext.fTypes.fFloatLiteral))) {
700         // In cases like half(float), they're different types as far as SkSL is concerned but
701         // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
702         // writing out the inner expression here.
703         this->writeExpression(argument, parentPrecedence);
704         return;
705     }
706 
707     // This cast should be emitted as-is.
708     return this->writeAnyConstructor(c, parentPrecedence);
709 }
710 
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)711 void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
712     this->writeType(c.type());
713     this->write("(");
714     const char* separator = "";
715     for (const auto& arg : c.argumentSpan()) {
716         this->write(separator);
717         separator = ", ";
718         this->writeExpression(*arg, Precedence::kSequence);
719     }
720     this->write(")");
721 }
722 
writeFragCoord()723 void GLSLCodeGenerator::writeFragCoord() {
724     if (!this->caps().canUseFragCoord()) {
725         if (!fSetupFragCoordWorkaround) {
726             const char* precision = usesPrecisionModifiers() ? "highp " : "";
727             fFunctionHeader += precision;
728             fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
729             fFunctionHeader += precision;
730             fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
731                 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
732             // Ensure that we get exact .5 values for x and y.
733             fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
734                                "vec2(.5);\n";
735             fSetupFragCoordWorkaround = true;
736         }
737         this->write("sk_FragCoord_Resolved");
738         return;
739     }
740 
741     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
742     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
743     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
744     if (!fProgram.fConfig->fSettings.fFlipY) {
745         this->write("gl_FragCoord");
746     } else if (const char* extension = this->caps().fragCoordConventionsExtensionString()) {
747         if (!fSetupFragPositionGlobal) {
748             if (this->caps().generation() < k150_GrGLSLGeneration) {
749                 this->writeExtension(extension);
750             }
751             fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
752             fSetupFragPositionGlobal = true;
753         }
754         this->write("gl_FragCoord");
755     } else {
756         if (!fSetupFragPositionLocal) {
757             fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
758             fFunctionHeader += "    vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
759                                " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
760             fSetupFragPositionLocal = true;
761         }
762         this->write("sk_FragCoord");
763     }
764 }
765 
writeVariableReference(const VariableReference & ref)766 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
767     switch (ref.variable()->modifiers().fLayout.fBuiltin) {
768         case SK_FRAGCOLOR_BUILTIN:
769             if (this->caps().mustDeclareFragmentShaderOutput()) {
770                 this->write("sk_FragColor");
771             } else {
772                 this->write("gl_FragColor");
773             }
774             break;
775         case SK_FRAGCOORD_BUILTIN:
776             this->writeFragCoord();
777             break;
778         case SK_CLOCKWISE_BUILTIN:
779             this->write(fProgram.fConfig->fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
780             break;
781         case SK_VERTEXID_BUILTIN:
782             this->write("gl_VertexID");
783             break;
784         case SK_INSTANCEID_BUILTIN:
785             this->write("gl_InstanceID");
786             break;
787         case SK_IN_BUILTIN:
788             this->write("gl_in");
789             break;
790         case SK_INVOCATIONID_BUILTIN:
791             this->write("gl_InvocationID");
792             break;
793         case SK_LASTFRAGCOLOR_BUILTIN:
794             this->write(this->caps().fbFetchColorName());
795             break;
796         default:
797             this->write(ref.variable()->name());
798     }
799 }
800 
writeIndexExpression(const IndexExpression & expr)801 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
802     this->writeExpression(*expr.base(), Precedence::kPostfix);
803     this->write("[");
804     this->writeExpression(*expr.index(), Precedence::kTopLevel);
805     this->write("]");
806 }
807 
is_sk_position(const FieldAccess & f)808 bool is_sk_position(const FieldAccess& f) {
809     return "sk_Position" == f.base()->type().fields()[f.fieldIndex()].fName;
810 }
811 
writeFieldAccess(const FieldAccess & f)812 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
813     if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
814         this->writeExpression(*f.base(), Precedence::kPostfix);
815         this->write(".");
816     }
817     const Type& baseType = f.base()->type();
818     StringFragment name = baseType.fields()[f.fieldIndex()].fName;
819     if (name == "sk_Position") {
820         this->write("gl_Position");
821     } else if (name == "sk_PointSize") {
822         this->write("gl_PointSize");
823     } else {
824         this->write(baseType.fields()[f.fieldIndex()].fName);
825     }
826 }
827 
writeSwizzle(const Swizzle & swizzle)828 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
829     this->writeExpression(*swizzle.base(), Precedence::kPostfix);
830     this->write(".");
831     for (int c : swizzle.components()) {
832         SkASSERT(c >= 0 && c <= 3);
833         this->write(&("x\0y\0z\0w\0"[c * 2]));
834     }
835 }
836 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)837 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
838                                               Precedence parentPrecedence) {
839     const Expression& left = *b.left();
840     const Expression& right = *b.right();
841     Operator op = b.getOperator();
842     if (this->caps().unfoldShortCircuitAsTernary() &&
843             (op.kind() == Token::Kind::TK_LOGICALAND || op.kind() == Token::Kind::TK_LOGICALOR)) {
844         this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
845         return;
846     }
847 
848     Precedence precedence = op.getBinaryPrecedence();
849     if (precedence >= parentPrecedence) {
850         this->write("(");
851     }
852     bool positionWorkaround = fProgram.fConfig->fKind == ProgramKind::kVertex &&
853                               op.isAssignment() &&
854                               left.is<FieldAccess>() &&
855                               is_sk_position(left.as<FieldAccess>()) &&
856                               !right.containsRTAdjust() &&
857                               !this->caps().canUseFragCoord();
858     if (positionWorkaround) {
859         this->write("sk_FragCoord_Workaround = (");
860     }
861     this->writeExpression(left, precedence);
862     this->write(" ");
863     this->write(op.operatorName());
864     this->write(" ");
865     this->writeExpression(right, precedence);
866     if (positionWorkaround) {
867         this->write(")");
868     }
869     if (precedence >= parentPrecedence) {
870         this->write(")");
871     }
872 }
873 
writeShortCircuitWorkaroundExpression(const BinaryExpression & b,Precedence parentPrecedence)874 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
875                                                               Precedence parentPrecedence) {
876     if (Precedence::kTernary >= parentPrecedence) {
877         this->write("(");
878     }
879 
880     // Transform:
881     // a && b  =>   a ? b : false
882     // a || b  =>   a ? true : b
883     this->writeExpression(*b.left(), Precedence::kTernary);
884     this->write(" ? ");
885     if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
886         this->writeExpression(*b.right(), Precedence::kTernary);
887     } else {
888         BoolLiteral boolTrue(/*offset=*/-1, /*value=*/true, fContext.fTypes.fBool.get());
889         this->writeBoolLiteral(boolTrue);
890     }
891     this->write(" : ");
892     if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
893         BoolLiteral boolFalse(/*offset=*/-1, /*value=*/false, fContext.fTypes.fBool.get());
894         this->writeBoolLiteral(boolFalse);
895     } else {
896         this->writeExpression(*b.right(), Precedence::kTernary);
897     }
898     if (Precedence::kTernary >= parentPrecedence) {
899         this->write(")");
900     }
901 }
902 
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)903 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
904                                                Precedence parentPrecedence) {
905     if (Precedence::kTernary >= parentPrecedence) {
906         this->write("(");
907     }
908     this->writeExpression(*t.test(), Precedence::kTernary);
909     this->write(" ? ");
910     this->writeExpression(*t.ifTrue(), Precedence::kTernary);
911     this->write(" : ");
912     this->writeExpression(*t.ifFalse(), Precedence::kTernary);
913     if (Precedence::kTernary >= parentPrecedence) {
914         this->write(")");
915     }
916 }
917 
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)918 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
919                                               Precedence parentPrecedence) {
920     if (Precedence::kPrefix >= parentPrecedence) {
921         this->write("(");
922     }
923     this->write(p.getOperator().operatorName());
924     this->writeExpression(*p.operand(), Precedence::kPrefix);
925     if (Precedence::kPrefix >= parentPrecedence) {
926         this->write(")");
927     }
928 }
929 
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)930 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
931                                                Precedence parentPrecedence) {
932     if (Precedence::kPostfix >= parentPrecedence) {
933         this->write("(");
934     }
935     this->writeExpression(*p.operand(), Precedence::kPostfix);
936     this->write(p.getOperator().operatorName());
937     if (Precedence::kPostfix >= parentPrecedence) {
938         this->write(")");
939     }
940 }
941 
writeBoolLiteral(const BoolLiteral & b)942 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
943     this->write(b.value() ? "true" : "false");
944 }
945 
writeIntLiteral(const IntLiteral & i)946 void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
947     const Type& type = i.type();
948     if (type == *fContext.fTypes.fUInt) {
949         this->write(to_string(i.value() & 0xffffffff) + "u");
950     } else if (type == *fContext.fTypes.fUShort) {
951         this->write(to_string(i.value() & 0xffff) + "u");
952     } else {
953         this->write(to_string(i.value()));
954     }
955 }
956 
writeFloatLiteral(const FloatLiteral & f)957 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
958     this->write(to_string(f.value()));
959 }
960 
writeSetting(const Setting & s)961 void GLSLCodeGenerator::writeSetting(const Setting& s) {
962     SK_ABORT("internal error; setting was not folded to a constant during compilation\n");
963 }
964 
writeFunctionDeclaration(const FunctionDeclaration & f)965 void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) {
966     this->writeTypePrecision(f.returnType());
967     this->writeType(f.returnType());
968     this->write(" " + f.mangledName() + "(");
969     const char* separator = "";
970     for (const auto& param : f.parameters()) {
971         // This is a workaround for our test files. They use the runtime effect signature, so main
972         // takes a coords parameter. The IR generator tags those with a builtin ID (sk_FragCoord),
973         // and we omit them from the declaration here, so the function is valid GLSL.
974         if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) {
975             continue;
976         }
977         this->write(separator);
978         separator = ", ";
979         this->writeModifiers(param->modifiers(), false);
980         std::vector<int> sizes;
981         const Type* type = &param->type();
982         if (type->isArray()) {
983             sizes.push_back(type->columns());
984             type = &type->componentType();
985         }
986         this->writeTypePrecision(*type);
987         this->writeType(*type);
988         this->write(" " + param->name());
989         for (int s : sizes) {
990             if (s == Type::kUnsizedArray) {
991                 this->write("[]");
992             } else {
993                 this->write("[" + to_string(s) + "]");
994             }
995         }
996     }
997     this->write(")");
998 }
999 
writeFunction(const FunctionDefinition & f)1000 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1001     fSetupFragPositionLocal = false;
1002     fSetupFragCoordWorkaround = false;
1003 
1004     this->writeFunctionDeclaration(f.declaration());
1005     this->writeLine(" {");
1006     fIndentation++;
1007 
1008     fFunctionHeader.clear();
1009     OutputStream* oldOut = fOut;
1010     StringStream buffer;
1011     fOut = &buffer;
1012     for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
1013         if (!stmt->isEmpty()) {
1014             this->writeStatement(*stmt);
1015             this->finishLine();
1016         }
1017     }
1018 
1019     fIndentation--;
1020     this->writeLine("}");
1021 
1022     fOut = oldOut;
1023     this->write(fFunctionHeader);
1024     this->write(buffer.str());
1025 }
1026 
writeFunctionPrototype(const FunctionPrototype & f)1027 void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
1028     this->writeFunctionDeclaration(f.declaration());
1029     this->writeLine(";");
1030 }
1031 
writeModifiers(const Modifiers & modifiers,bool globalContext)1032 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
1033                                        bool globalContext) {
1034     if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1035         this->write("flat ");
1036     }
1037     if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1038         this->write("noperspective ");
1039     }
1040     String layout = modifiers.fLayout.description();
1041     if (layout.size()) {
1042         this->write(layout + " ");
1043     }
1044     if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
1045         (modifiers.fFlags & Modifiers::kOut_Flag)) {
1046         this->write("inout ");
1047     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
1048         if (globalContext &&
1049             this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1050             this->write(fProgram.fConfig->fKind == ProgramKind::kVertex ? "attribute "
1051                                                                         : "varying ");
1052         } else {
1053             this->write("in ");
1054         }
1055     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1056         if (globalContext &&
1057             this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1058             this->write("varying ");
1059         } else {
1060             this->write("out ");
1061         }
1062     }
1063     if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1064         this->write("uniform ");
1065     }
1066     if (modifiers.fFlags & Modifiers::kConst_Flag) {
1067         this->write("const ");
1068     }
1069 }
1070 
writeInterfaceBlock(const InterfaceBlock & intf)1071 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1072     if (intf.typeName() == "sk_PerVertex") {
1073         return;
1074     }
1075     this->writeModifiers(intf.variable().modifiers(), true);
1076     this->writeLine(intf.typeName() + " {");
1077     fIndentation++;
1078     const Type* structType = &intf.variable().type();
1079     if (structType->isArray()) {
1080         structType = &structType->componentType();
1081     }
1082     for (const auto& f : structType->fields()) {
1083         this->writeModifiers(f.fModifiers, false);
1084         this->writeTypePrecision(*f.fType);
1085         this->writeType(*f.fType);
1086         this->writeLine(" " + f.fName + ";");
1087     }
1088     fIndentation--;
1089     this->write("}");
1090     if (intf.instanceName().size()) {
1091         this->write(" ");
1092         this->write(intf.instanceName());
1093         if (intf.arraySize() > 0) {
1094             this->write("[");
1095             this->write(to_string(intf.arraySize()));
1096             this->write("]");
1097         } else if (intf.arraySize() == Type::kUnsizedArray){
1098             this->write("[]");
1099         }
1100     }
1101     this->writeLine(";");
1102 }
1103 
writeVarInitializer(const Variable & var,const Expression & value)1104 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1105     this->writeExpression(value, Precedence::kTopLevel);
1106 }
1107 
getTypePrecision(const Type & type)1108 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1109     if (usesPrecisionModifiers()) {
1110         switch (type.typeKind()) {
1111             case Type::TypeKind::kScalar:
1112                 if (type == *fContext.fTypes.fShort || type == *fContext.fTypes.fUShort) {
1113                     if (fProgram.fConfig->fSettings.fForceHighPrecision ||
1114                             this->caps().incompleteShortIntPrecision()) {
1115                         return "highp ";
1116                     }
1117                     return "mediump ";
1118                 }
1119                 if (type == *fContext.fTypes.fHalf) {
1120                     return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
1121                 }
1122                 if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fInt ||
1123                         type == *fContext.fTypes.fUInt) {
1124                     return "highp ";
1125                 }
1126                 return "";
1127             case Type::TypeKind::kVector: // fall through
1128             case Type::TypeKind::kMatrix:
1129             case Type::TypeKind::kArray:
1130                 return this->getTypePrecision(type.componentType());
1131             default:
1132                 break;
1133         }
1134     }
1135     return "";
1136 }
1137 
writeTypePrecision(const Type & type)1138 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1139     this->write(this->getTypePrecision(type));
1140 }
1141 
writeVarDeclaration(const VarDeclaration & var,bool global)1142 void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
1143     this->writeModifiers(var.var().modifiers(), global);
1144     this->writeTypePrecision(var.baseType());
1145     this->writeType(var.baseType());
1146     this->write(" ");
1147     this->write(var.var().name());
1148     if (var.arraySize() > 0) {
1149         this->write("[");
1150         this->write(to_string(var.arraySize()));
1151         this->write("]");
1152     } else if (var.arraySize() == Type::kUnsizedArray){
1153         this->write("[]");
1154     }
1155     if (var.value()) {
1156         this->write(" = ");
1157         this->writeVarInitializer(var.var(), *var.value());
1158     }
1159     if (!fFoundExternalSamplerDecl && var.var().type() == *fContext.fTypes.fSamplerExternalOES) {
1160         if (this->caps().externalTextureExtensionString()) {
1161             this->writeExtension(this->caps().externalTextureExtensionString());
1162         }
1163         if (this->caps().secondExternalTextureExtensionString()) {
1164             this->writeExtension(this->caps().secondExternalTextureExtensionString());
1165         }
1166         fFoundExternalSamplerDecl = true;
1167     }
1168     if (!fFoundRectSamplerDecl && var.var().type() == *fContext.fTypes.fSampler2DRect) {
1169         fFoundRectSamplerDecl = true;
1170     }
1171     this->write(";");
1172 }
1173 
writeStatement(const Statement & s)1174 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1175     switch (s.kind()) {
1176         case Statement::Kind::kBlock:
1177             this->writeBlock(s.as<Block>());
1178             break;
1179         case Statement::Kind::kExpression:
1180             this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
1181             this->write(";");
1182             break;
1183         case Statement::Kind::kReturn:
1184             this->writeReturnStatement(s.as<ReturnStatement>());
1185             break;
1186         case Statement::Kind::kVarDeclaration:
1187             this->writeVarDeclaration(s.as<VarDeclaration>(), false);
1188             break;
1189         case Statement::Kind::kIf:
1190             this->writeIfStatement(s.as<IfStatement>());
1191             break;
1192         case Statement::Kind::kFor:
1193             this->writeForStatement(s.as<ForStatement>());
1194             break;
1195         case Statement::Kind::kDo:
1196             this->writeDoStatement(s.as<DoStatement>());
1197             break;
1198         case Statement::Kind::kSwitch:
1199             this->writeSwitchStatement(s.as<SwitchStatement>());
1200             break;
1201         case Statement::Kind::kBreak:
1202             this->write("break;");
1203             break;
1204         case Statement::Kind::kContinue:
1205             this->write("continue;");
1206             break;
1207         case Statement::Kind::kDiscard:
1208             this->write("discard;");
1209             break;
1210         case Statement::Kind::kInlineMarker:
1211         case Statement::Kind::kNop:
1212             this->write(";");
1213             break;
1214         default:
1215             SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
1216             break;
1217     }
1218 }
1219 
writeBlock(const Block & b)1220 void GLSLCodeGenerator::writeBlock(const Block& b) {
1221     // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1222     // something here to make the code valid).
1223     bool isScope = b.isScope() || b.isEmpty();
1224     if (isScope) {
1225         this->writeLine("{");
1226         fIndentation++;
1227     }
1228     for (const std::unique_ptr<Statement>& stmt : b.children()) {
1229         if (!stmt->isEmpty()) {
1230             this->writeStatement(*stmt);
1231             this->finishLine();
1232         }
1233     }
1234     if (isScope) {
1235         fIndentation--;
1236         this->write("}");
1237     }
1238 }
1239 
writeIfStatement(const IfStatement & stmt)1240 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1241     this->write("if (");
1242     this->writeExpression(*stmt.test(), Precedence::kTopLevel);
1243     this->write(") ");
1244     this->writeStatement(*stmt.ifTrue());
1245     if (stmt.ifFalse()) {
1246         this->write(" else ");
1247         this->writeStatement(*stmt.ifFalse());
1248     }
1249 }
1250 
writeForStatement(const ForStatement & f)1251 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1252     // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1253     if (!f.initializer() && f.test() && !f.next()) {
1254         this->write("while (");
1255         this->writeExpression(*f.test(), Precedence::kTopLevel);
1256         this->write(") ");
1257         this->writeStatement(*f.statement());
1258         return;
1259     }
1260 
1261     this->write("for (");
1262     if (f.initializer() && !f.initializer()->isEmpty()) {
1263         this->writeStatement(*f.initializer());
1264     } else {
1265         this->write("; ");
1266     }
1267     if (f.test()) {
1268         if (this->caps().addAndTrueToLoopCondition()) {
1269             std::unique_ptr<Expression> and_true(new BinaryExpression(
1270                     /*offset=*/-1, f.test()->clone(), Token::Kind::TK_LOGICALAND,
1271                     BoolLiteral::Make(fContext, /*offset=*/-1, /*value=*/true),
1272                     fContext.fTypes.fBool.get()));
1273             this->writeExpression(*and_true, Precedence::kTopLevel);
1274         } else {
1275             this->writeExpression(*f.test(), Precedence::kTopLevel);
1276         }
1277     }
1278     this->write("; ");
1279     if (f.next()) {
1280         this->writeExpression(*f.next(), Precedence::kTopLevel);
1281     }
1282     this->write(") ");
1283     this->writeStatement(*f.statement());
1284 }
1285 
writeDoStatement(const DoStatement & d)1286 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1287     if (!this->caps().rewriteDoWhileLoops()) {
1288         this->write("do ");
1289         this->writeStatement(*d.statement());
1290         this->write(" while (");
1291         this->writeExpression(*d.test(), Precedence::kTopLevel);
1292         this->write(");");
1293         return;
1294     }
1295 
1296     // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1297     //     do {
1298     //         CODE;
1299     //     } while (CONDITION)
1300     //
1301     // to loops of the form
1302     //     bool temp = false;
1303     //     while (true) {
1304     //         if (temp) {
1305     //             if (!CONDITION) {
1306     //                 break;
1307     //             }
1308     //         }
1309     //         temp = true;
1310     //         CODE;
1311     //     }
1312     String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1313     this->write("bool ");
1314     this->write(tmpVar);
1315     this->writeLine(" = false;");
1316     this->writeLine("while (true) {");
1317     fIndentation++;
1318     this->write("if (");
1319     this->write(tmpVar);
1320     this->writeLine(") {");
1321     fIndentation++;
1322     this->write("if (!");
1323     this->writeExpression(*d.test(), Precedence::kPrefix);
1324     this->writeLine(") {");
1325     fIndentation++;
1326     this->writeLine("break;");
1327     fIndentation--;
1328     this->writeLine("}");
1329     fIndentation--;
1330     this->writeLine("}");
1331     this->write(tmpVar);
1332     this->writeLine(" = true;");
1333     this->writeStatement(*d.statement());
1334     this->finishLine();
1335     fIndentation--;
1336     this->write("}");
1337 }
1338 
writeSwitchStatement(const SwitchStatement & s)1339 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1340     this->write("switch (");
1341     this->writeExpression(*s.value(), Precedence::kTopLevel);
1342     this->writeLine(") {");
1343     fIndentation++;
1344     for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1345         const SwitchCase& c = stmt->as<SwitchCase>();
1346         if (c.value()) {
1347             this->write("case ");
1348             this->writeExpression(*c.value(), Precedence::kTopLevel);
1349             this->writeLine(":");
1350         } else {
1351             this->writeLine("default:");
1352         }
1353         if (!c.statement()->isEmpty()) {
1354             fIndentation++;
1355             this->writeStatement(*c.statement());
1356             this->finishLine();
1357             fIndentation--;
1358         }
1359     }
1360     fIndentation--;
1361     this->finishLine();
1362     this->write("}");
1363 }
1364 
writeReturnStatement(const ReturnStatement & r)1365 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1366     this->write("return");
1367     if (r.expression()) {
1368         this->write(" ");
1369         this->writeExpression(*r.expression(), Precedence::kTopLevel);
1370     }
1371     this->write(";");
1372 }
1373 
writeHeader()1374 void GLSLCodeGenerator::writeHeader() {
1375     if (this->caps().versionDeclString()) {
1376         this->write(this->caps().versionDeclString());
1377         this->finishLine();
1378     }
1379 }
1380 
writeProgramElement(const ProgramElement & e)1381 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1382     switch (e.kind()) {
1383         case ProgramElement::Kind::kExtension:
1384             this->writeExtension(e.as<Extension>().name());
1385             break;
1386         case ProgramElement::Kind::kGlobalVar: {
1387             const VarDeclaration& decl =
1388                                    e.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
1389             int builtin = decl.var().modifiers().fLayout.fBuiltin;
1390             if (builtin == -1) {
1391                 // normal var
1392                 this->writeVarDeclaration(decl, true);
1393                 this->finishLine();
1394             } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1395                        this->caps().mustDeclareFragmentShaderOutput()) {
1396                 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
1397                     this->write("inout ");
1398                 } else {
1399                     this->write("out ");
1400                 }
1401                 if (usesPrecisionModifiers()) {
1402                     this->write("mediump ");
1403                 }
1404                 this->writeLine("vec4 sk_FragColor;");
1405             }
1406             break;
1407         }
1408         case ProgramElement::Kind::kInterfaceBlock:
1409             this->writeInterfaceBlock(e.as<InterfaceBlock>());
1410             break;
1411         case ProgramElement::Kind::kFunction:
1412             this->writeFunction(e.as<FunctionDefinition>());
1413             break;
1414         case ProgramElement::Kind::kFunctionPrototype:
1415             this->writeFunctionPrototype(e.as<FunctionPrototype>());
1416             break;
1417         case ProgramElement::Kind::kModifiers: {
1418             const Modifiers& modifiers = e.as<ModifiersDeclaration>().modifiers();
1419             if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1420                 if (this->caps().gsInvocationsExtensionString()) {
1421                     this->writeExtension(this->caps().gsInvocationsExtensionString());
1422                 }
1423                 fFoundGSInvocations = true;
1424             }
1425             this->writeModifiers(modifiers, true);
1426             this->writeLine(";");
1427             break;
1428         }
1429         case ProgramElement::Kind::kEnum:
1430             break;
1431         case ProgramElement::Kind::kStructDefinition:
1432             this->writeStructDefinition(e.as<StructDefinition>());
1433             break;
1434         default:
1435             SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1436             break;
1437     }
1438 }
1439 
writeInputVars()1440 void GLSLCodeGenerator::writeInputVars() {
1441     if (fProgram.fInputs.fRTHeight) {
1442         const char* precision = usesPrecisionModifiers() ? "highp " : "";
1443         fGlobals.writeText("uniform ");
1444         fGlobals.writeText(precision);
1445         fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1446     }
1447 }
1448 
generateCode()1449 bool GLSLCodeGenerator::generateCode() {
1450     this->writeHeader();
1451     if (fProgram.fConfig->fKind == ProgramKind::kGeometry &&
1452         this->caps().geometryShaderExtensionString()) {
1453         this->writeExtension(this->caps().geometryShaderExtensionString());
1454     }
1455     OutputStream* rawOut = fOut;
1456     StringStream body;
1457     fOut = &body;
1458     // Write all the program elements except for functions.
1459     for (const ProgramElement* e : fProgram.elements()) {
1460         if (!e->is<FunctionDefinition>()) {
1461             this->writeProgramElement(*e);
1462         }
1463     }
1464     // Write the functions last.
1465     // Why don't we write things in their original order? Because the Inliner likes to move function
1466     // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
1467     // that the code relies on.
1468     for (const ProgramElement* e : fProgram.elements()) {
1469         if (e->is<FunctionDefinition>()) {
1470             this->writeProgramElement(*e);
1471         }
1472     }
1473     fOut = rawOut;
1474 
1475     write_stringstream(fExtensions, *rawOut);
1476     this->writeInputVars();
1477     write_stringstream(fGlobals, *rawOut);
1478 
1479     if (!this->caps().canUseFragCoord()) {
1480         Layout layout;
1481         switch (fProgram.fConfig->fKind) {
1482             case ProgramKind::kVertex: {
1483                 Modifiers modifiers(layout, Modifiers::kOut_Flag);
1484                 this->writeModifiers(modifiers, true);
1485                 if (this->usesPrecisionModifiers()) {
1486                     this->write("highp ");
1487                 }
1488                 this->write("vec4 sk_FragCoord_Workaround;\n");
1489                 break;
1490             }
1491             case ProgramKind::kFragment: {
1492                 Modifiers modifiers(layout, Modifiers::kIn_Flag);
1493                 this->writeModifiers(modifiers, true);
1494                 if (this->usesPrecisionModifiers()) {
1495                     this->write("highp ");
1496                 }
1497                 this->write("vec4 sk_FragCoord_Workaround;\n");
1498                 break;
1499             }
1500             default:
1501                 break;
1502         }
1503     }
1504 
1505     if (this->usesPrecisionModifiers()) {
1506         this->writeLine("precision mediump float;");
1507         this->writeLine("precision mediump sampler2D;");
1508         if (fFoundExternalSamplerDecl &&
1509             !this->caps().noDefaultPrecisionForExternalSamplers()) {
1510             this->writeLine("precision mediump samplerExternalOES;");
1511         }
1512         if (fFoundRectSamplerDecl) {
1513             this->writeLine("precision mediump sampler2DRect;");
1514         }
1515     }
1516     write_stringstream(fExtraFunctions, *rawOut);
1517     write_stringstream(body, *rawOut);
1518     return 0 == fErrors.errorCount();
1519 }
1520 
1521 }  // namespace SkSL
1522