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