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