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