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