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