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