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