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 "SkSLGLSLCodeGenerator.h"
9
10#include "SkSLCompiler.h"
11#include "ir/SkSLExpressionStatement.h"
12#include "ir/SkSLExtension.h"
13#include "ir/SkSLIndexExpression.h"
14#include "ir/SkSLModifiersDeclaration.h"
15#include "ir/SkSLNop.h"
16#include "ir/SkSLVariableReference.h"
17
18namespace SkSL {
19
20void GLSLCodeGenerator::write(const char* s) {
21    if (s[0] == 0) {
22        return;
23    }
24    if (fAtLineStart) {
25        for (int i = 0; i < fIndentation; i++) {
26            fOut->writeText("    ");
27        }
28    }
29    fOut->writeText(s);
30    fAtLineStart = false;
31}
32
33void GLSLCodeGenerator::writeLine(const char* s) {
34    this->write(s);
35    fOut->writeText(fLineEnding);
36    fAtLineStart = true;
37}
38
39void GLSLCodeGenerator::write(const String& s) {
40    this->write(s.c_str());
41}
42
43void GLSLCodeGenerator::write(StringFragment s) {
44    if (!s.fLength) {
45        return;
46    }
47    if (fAtLineStart) {
48        for (int i = 0; i < fIndentation; i++) {
49            fOut->writeText("    ");
50        }
51    }
52    fOut->write(s.fChars, s.fLength);
53    fAtLineStart = false;
54}
55
56void GLSLCodeGenerator::writeLine(const String& s) {
57    this->writeLine(s.c_str());
58}
59
60void GLSLCodeGenerator::writeLine() {
61    this->writeLine("");
62}
63
64void GLSLCodeGenerator::writeExtension(const Extension& ext) {
65    this->write("#extension ");
66    this->write(ext.fName);
67    this->writeLine(" : enable");
68}
69
70bool GLSLCodeGenerator::usesPrecisionModifiers() const {
71    return fProgram.fSettings.fCaps->usesPrecisionModifiers();
72}
73
74String GLSLCodeGenerator::getTypeName(const Type& type) {
75    switch (type.kind()) {
76        case Type::kVector_Kind: {
77            Type component = type.componentType();
78            String result;
79            if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
80                result = "vec";
81            }
82            else if (component == *fContext.fDouble_Type) {
83                result = "dvec";
84            }
85            else if (component == *fContext.fInt_Type || component == *fContext.fShort_Type) {
86                result = "ivec";
87            }
88            else if (component == *fContext.fUInt_Type || component == *fContext.fUShort_Type) {
89                result = "uvec";
90            }
91            else if (component == *fContext.fBool_Type) {
92                result = "bvec";
93            }
94            else {
95                ABORT("unsupported vector type");
96            }
97            result += to_string(type.columns());
98            return result;
99        }
100        case Type::kMatrix_Kind: {
101            String result;
102            Type component = type.componentType();
103            if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
104                result = "mat";
105            }
106            else if (component == *fContext.fDouble_Type) {
107                result = "dmat";
108            }
109            else {
110                ABORT("unsupported matrix type");
111            }
112            result += to_string(type.columns());
113            if (type.columns() != type.rows()) {
114                result += "x";
115                result += to_string(type.rows());
116            }
117            return result;
118        }
119        case Type::kArray_Kind: {
120            String result = this->getTypeName(type.componentType()) + "[";
121            if (type.columns() != -1) {
122                result += to_string(type.columns());
123            }
124            result += "]";
125            return result;
126        }
127        case Type::kScalar_Kind: {
128            if (type == *fContext.fHalf_Type) {
129                return "float";
130            }
131            else if (type == *fContext.fShort_Type) {
132                return "int";
133            }
134            else if (type == *fContext.fUShort_Type) {
135                return "uint";
136            }
137            else {
138                return type.name();
139            }
140            break;
141        }
142        default:
143            return type.name();
144    }
145}
146
147void GLSLCodeGenerator::writeType(const Type& type) {
148    if (type.kind() == Type::kStruct_Kind) {
149        for (const Type* search : fWrittenStructs) {
150            if (*search == type) {
151                // already written
152                this->write(type.fName);
153                return;
154            }
155        }
156        fWrittenStructs.push_back(&type);
157        this->write("struct ");
158        this->write(type.fName);
159        this->writeLine(" {");
160        fIndentation++;
161        for (const auto& f : type.fields()) {
162            this->writeModifiers(f.fModifiers, false);
163            this->writeTypePrecision(*f.fType);
164            // sizes (which must be static in structs) are part of the type name here
165            this->writeType(*f.fType);
166            this->write(" ");
167            this->write(f.fName);
168            this->writeLine(";");
169        }
170        fIndentation--;
171        this->write("}");
172    } else {
173        this->write(this->getTypeName(type));
174    }
175}
176
177void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
178    switch (expr.fKind) {
179        case Expression::kBinary_Kind:
180            this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
181            break;
182        case Expression::kBoolLiteral_Kind:
183            this->writeBoolLiteral((BoolLiteral&) expr);
184            break;
185        case Expression::kConstructor_Kind:
186            this->writeConstructor((Constructor&) expr, parentPrecedence);
187            break;
188        case Expression::kIntLiteral_Kind:
189            this->writeIntLiteral((IntLiteral&) expr);
190            break;
191        case Expression::kFieldAccess_Kind:
192            this->writeFieldAccess(((FieldAccess&) expr));
193            break;
194        case Expression::kFloatLiteral_Kind:
195            this->writeFloatLiteral(((FloatLiteral&) expr));
196            break;
197        case Expression::kFunctionCall_Kind:
198            this->writeFunctionCall((FunctionCall&) expr);
199            break;
200        case Expression::kPrefix_Kind:
201            this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
202            break;
203        case Expression::kPostfix_Kind:
204            this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
205            break;
206        case Expression::kSetting_Kind:
207            this->writeSetting((Setting&) expr);
208            break;
209        case Expression::kSwizzle_Kind:
210            this->writeSwizzle((Swizzle&) expr);
211            break;
212        case Expression::kVariableReference_Kind:
213            this->writeVariableReference((VariableReference&) expr);
214            break;
215        case Expression::kTernary_Kind:
216            this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
217            break;
218        case Expression::kIndex_Kind:
219            this->writeIndexExpression((IndexExpression&) expr);
220            break;
221        default:
222            ABORT("unsupported expression: %s", expr.description().c_str());
223    }
224}
225
226static bool is_abs(Expression& expr) {
227    if (expr.fKind != Expression::kFunctionCall_Kind) {
228        return false;
229    }
230    return ((FunctionCall&) expr).fFunction.fName == "abs";
231}
232
233// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
234// Tegra3 compiler bug.
235void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
236    ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
237    String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
238    String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
239    this->fFunctionHeader += String("    ") + this->getTypePrecision(absExpr.fType) +
240                             this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
241    this->fFunctionHeader += String("    ") + this->getTypePrecision(otherExpr.fType) +
242                             this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
243    this->write("((" + tmpVar1 + " = ");
244    this->writeExpression(absExpr, kTopLevel_Precedence);
245    this->write(") < (" + tmpVar2 + " = ");
246    this->writeExpression(otherExpr, kAssignment_Precedence);
247    this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
248}
249
250void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
251    this->write("(1.0 / sqrt(");
252    this->writeExpression(x, kTopLevel_Precedence);
253    this->write("))");
254}
255
256void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
257    String name;
258    if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
259        name = "_determinant2";
260        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
261            fWrittenIntrinsics.insert(name);
262            fExtraFunctions.writeText((
263                "float " + name + "(mat2 m) {"
264                "    return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
265                "}"
266            ).c_str());
267        }
268    }
269    else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
270        name = "_determinant3";
271        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
272            fWrittenIntrinsics.insert(name);
273            fExtraFunctions.writeText((
274                "float " + name + "(mat3 m) {"
275                "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
276                "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
277                "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
278                "    float b01 = a22 * a11 - a12 * a21;"
279                "    float b11 = -a22 * a10 + a12 * a20;"
280                "    float b21 = a21 * a10 - a11 * a20;"
281                "    return a00 * b01 + a01 * b11 + a02 * b21;"
282                "}"
283            ).c_str());
284        }
285    }
286    else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
287        name = "_determinant3";
288        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
289            fWrittenIntrinsics.insert(name);
290            fExtraFunctions.writeText((
291                "mat4 " + name + "(mat4 m) {"
292                "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
293                "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
294                "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
295                "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
296                "    float b00 = a00 * a11 - a01 * a10;"
297                "    float b01 = a00 * a12 - a02 * a10;"
298                "    float b02 = a00 * a13 - a03 * a10;"
299                "    float b03 = a01 * a12 - a02 * a11;"
300                "    float b04 = a01 * a13 - a03 * a11;"
301                "    float b05 = a02 * a13 - a03 * a12;"
302                "    float b06 = a20 * a31 - a21 * a30;"
303                "    float b07 = a20 * a32 - a22 * a30;"
304                "    float b08 = a20 * a33 - a23 * a30;"
305                "    float b09 = a21 * a32 - a22 * a31;"
306                "    float b10 = a21 * a33 - a23 * a31;"
307                "    float b11 = a22 * a33 - a23 * a32;"
308                "    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
309                "}"
310            ).c_str());
311        }
312    }
313    else {
314        ASSERT(false);
315    }
316    this->write(name + "(");
317    this->writeExpression(mat, kTopLevel_Precedence);
318    this->write(")");
319}
320
321void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
322    String name;
323    if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
324        name = "_inverse2";
325        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
326            fWrittenIntrinsics.insert(name);
327            fExtraFunctions.writeText((
328                "mat2 " + name + "(mat2 m) {"
329                "    return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
330                               "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
331                "}"
332            ).c_str());
333        }
334    }
335    else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
336        name = "_inverse3";
337        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
338            fWrittenIntrinsics.insert(name);
339            fExtraFunctions.writeText((
340                "mat3 " +  name + "(mat3 m) {"
341                "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
342                "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
343                "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
344                "    float b01 = a22 * a11 - a12 * a21;"
345                "    float b11 = -a22 * a10 + a12 * a20;"
346                "    float b21 = a21 * a10 - a11 * a20;"
347                "    float det = a00 * b01 + a01 * b11 + a02 * b21;"
348                "    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
349                "                b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
350                "                b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
351                "}"
352            ).c_str());
353        }
354    }
355    else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
356        name = "_inverse4";
357        if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
358            fWrittenIntrinsics.insert(name);
359            fExtraFunctions.writeText((
360                "mat4 " + name + "(mat4 m) {"
361                "    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
362                "    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
363                "    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
364                "    float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
365                "    float b00 = a00 * a11 - a01 * a10;"
366                "    float b01 = a00 * a12 - a02 * a10;"
367                "    float b02 = a00 * a13 - a03 * a10;"
368                "    float b03 = a01 * a12 - a02 * a11;"
369                "    float b04 = a01 * a13 - a03 * a11;"
370                "    float b05 = a02 * a13 - a03 * a12;"
371                "    float b06 = a20 * a31 - a21 * a30;"
372                "    float b07 = a20 * a32 - a22 * a30;"
373                "    float b08 = a20 * a33 - a23 * a30;"
374                "    float b09 = a21 * a32 - a22 * a31;"
375                "    float b10 = a21 * a33 - a23 * a31;"
376                "    float b11 = a22 * a33 - a23 * a32;"
377                "    float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
378                "                b04 * b07 + b05 * b06;"
379                "    return mat4("
380                "        a11 * b11 - a12 * b10 + a13 * b09,"
381                "        a02 * b10 - a01 * b11 - a03 * b09,"
382                "        a31 * b05 - a32 * b04 + a33 * b03,"
383                "        a22 * b04 - a21 * b05 - a23 * b03,"
384                "        a12 * b08 - a10 * b11 - a13 * b07,"
385                "        a00 * b11 - a02 * b08 + a03 * b07,"
386                "        a32 * b02 - a30 * b05 - a33 * b01,"
387                "        a20 * b05 - a22 * b02 + a23 * b01,"
388                "        a10 * b10 - a11 * b08 + a13 * b06,"
389                "        a01 * b08 - a00 * b10 - a03 * b06,"
390                "        a30 * b04 - a31 * b02 + a33 * b00,"
391                "        a21 * b02 - a20 * b04 - a23 * b00,"
392                "        a11 * b07 - a10 * b09 - a12 * b06,"
393                "        a00 * b09 - a01 * b07 + a02 * b06,"
394                "        a31 * b01 - a30 * b03 - a32 * b00,"
395                "        a20 * b03 - a21 * b01 + a22 * b00) / det;"
396                "}"
397            ).c_str());
398        }
399    }
400    else {
401        ASSERT(false);
402    }
403    this->write(name + "(");
404    this->writeExpression(mat, kTopLevel_Precedence);
405    this->write(")");
406}
407
408void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
409    String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
410    if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
411        fWrittenIntrinsics.insert(name);
412        String type = this->getTypeName(mat.fType);
413        const Type& base = mat.fType.componentType();
414        String transposed =  this->getTypeName(base.toCompound(fContext,
415                                                               mat.fType.rows(),
416                                                               mat.fType.columns()));
417        fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
418                                  transposed + "(").c_str());
419        const char* separator = "";
420        for (int row = 0; row < mat.fType.rows(); ++row) {
421            for (int column = 0; column < mat.fType.columns(); ++column) {
422                fExtraFunctions.writeText(separator);
423                fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
424                                           "]").c_str());
425                separator = ", ";
426            }
427        }
428        fExtraFunctions.writeText("); }");
429    }
430    this->write(name + "(");
431    this->writeExpression(mat, kTopLevel_Precedence);
432    this->write(")");
433}
434
435void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
436    if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
437        c.fFunction.fBuiltin) {
438        ASSERT(c.fArguments.size() == 2);
439        if (is_abs(*c.fArguments[0])) {
440            this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
441            return;
442        }
443        if (is_abs(*c.fArguments[1])) {
444            // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
445            // ever end up mattering, but it's worth calling out.
446            this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
447            return;
448        }
449    }
450    if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues() && c.fFunction.fName == "fract" &&
451        c.fFunction.fBuiltin) {
452        ASSERT(c.fArguments.size() == 1);
453
454        this->write("(0.5 - sign(");
455        this->writeExpression(*c.fArguments[0], kSequence_Precedence);
456        this->write(") * (0.5 - fract(abs(");
457        this->writeExpression(*c.fArguments[0], kSequence_Precedence);
458        this->write("))))");
459
460        return;
461    }
462    if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
463        c.fFunction.fName == "atan" &&
464        c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
465        c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
466        const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
467        if (p.fOperator == Token::MINUS) {
468            this->write("atan(");
469            this->writeExpression(*c.fArguments[0], kSequence_Precedence);
470            this->write(", -1.0 * ");
471            this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
472            this->write(")");
473            return;
474        }
475    }
476    if (c.fFunction.fBuiltin && c.fFunction.fName == "determinant" &&
477        fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
478        ASSERT(c.fArguments.size() == 1);
479        this->writeDeterminantHack(*c.fArguments[0]);
480        return;
481    }
482    if (c.fFunction.fBuiltin && c.fFunction.fName == "inverse" &&
483        fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
484        ASSERT(c.fArguments.size() == 1);
485        this->writeInverseHack(*c.fArguments[0]);
486        return;
487    }
488    if (c.fFunction.fBuiltin && c.fFunction.fName == "inverseSqrt" &&
489        fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
490        ASSERT(c.fArguments.size() == 1);
491        this->writeInverseSqrtHack(*c.fArguments[0]);
492        return;
493    }
494    if (c.fFunction.fBuiltin && c.fFunction.fName == "transpose" &&
495        fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
496        ASSERT(c.fArguments.size() == 1);
497        this->writeTransposeHack(*c.fArguments[0]);
498        return;
499    }
500    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
501        c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
502        ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
503        fHeader.writeText("#extension ");
504        fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
505        fHeader.writeText(" : require\n");
506        fFoundDerivatives = true;
507    }
508    bool isTextureFunctionWithBias = false;
509    if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
510        const char* dim = "";
511        bool proj = false;
512        switch (c.fArguments[0]->fType.dimensions()) {
513            case SpvDim1D:
514                dim = "1D";
515                isTextureFunctionWithBias = true;
516                if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
517                    proj = false;
518                } else {
519                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
520                    proj = true;
521                }
522                break;
523            case SpvDim2D:
524                dim = "2D";
525                if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
526                    isTextureFunctionWithBias = true;
527                }
528                if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
529                    proj = false;
530                } else {
531                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
532                    proj = true;
533                }
534                break;
535            case SpvDim3D:
536                dim = "3D";
537                isTextureFunctionWithBias = true;
538                if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
539                    proj = false;
540                } else {
541                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
542                    proj = true;
543                }
544                break;
545            case SpvDimCube:
546                dim = "Cube";
547                isTextureFunctionWithBias = true;
548                proj = false;
549                break;
550            case SpvDimRect:
551                dim = "Rect";
552                proj = false;
553                break;
554            case SpvDimBuffer:
555                ASSERT(false); // doesn't exist
556                dim = "Buffer";
557                proj = false;
558                break;
559            case SpvDimSubpassData:
560                ASSERT(false); // doesn't exist
561                dim = "SubpassData";
562                proj = false;
563                break;
564        }
565        this->write("texture");
566        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
567            this->write(dim);
568        }
569        if (proj) {
570            this->write("Proj");
571        }
572
573    } else {
574        this->write(c.fFunction.fName);
575    }
576    this->write("(");
577    const char* separator = "";
578    for (const auto& arg : c.fArguments) {
579        this->write(separator);
580        separator = ", ";
581        this->writeExpression(*arg, kSequence_Precedence);
582    }
583    if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
584        this->write(", -0.5");
585    }
586    this->write(")");
587}
588
589void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
590    if (c.fArguments.size() == 1 &&
591        this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
592        // in cases like half(float), they're different types as far as SkSL is concerned but the
593        // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
594        // out the inner expression here.
595        this->writeExpression(*c.fArguments[0], parentPrecedence);
596        return;
597    }
598    this->writeType(c.fType);
599    this->write("(");
600    const char* separator = "";
601    for (const auto& arg : c.fArguments) {
602        this->write(separator);
603        separator = ", ";
604        this->writeExpression(*arg, kSequence_Precedence);
605    }
606    this->write(")");
607}
608
609void GLSLCodeGenerator::writeFragCoord() {
610    if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
611        if (!fSetupFragCoordWorkaround) {
612            const char* precision = usesPrecisionModifiers() ? "highp " : "";
613            fFunctionHeader += precision;
614            fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
615            fFunctionHeader += precision;
616            fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
617                "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
618            // Ensure that we get exact .5 values for x and y.
619            fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
620                               "vec2(.5);\n";
621            fSetupFragCoordWorkaround = true;
622        }
623        this->write("sk_FragCoord_Resolved");
624        return;
625    }
626
627    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
628    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
629    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
630    if (!fProgram.fSettings.fFlipY) {
631        this->write("gl_FragCoord");
632    } else if (const char* extension =
633               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
634        if (!fSetupFragPositionGlobal) {
635            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
636                fHeader.writeText("#extension ");
637                fHeader.writeText(extension);
638                fHeader.writeText(" : require\n");
639            }
640            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
641            fSetupFragPositionGlobal = true;
642        }
643        this->write("gl_FragCoord");
644    } else {
645        if (!fSetupFragPositionGlobal) {
646            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
647            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
648            // depending on the surrounding code, accessing .xy with a uniform involved can
649            // do the same thing. Copying gl_FragCoord.xy into a temp float2 beforehand
650            // (and only accessing .xy) seems to "fix" things.
651            const char* precision = usesPrecisionModifiers() ? "highp " : "";
652            fHeader.writeText("uniform ");
653            fHeader.writeText(precision);
654            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
655            fSetupFragPositionGlobal = true;
656        }
657        if (!fSetupFragPositionLocal) {
658            const char* precision = usesPrecisionModifiers() ? "highp " : "";
659            fFunctionHeader += precision;
660            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
661            fFunctionHeader += precision;
662            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
663                               " - _sktmpCoord.y, 1.0, 1.0);\n";
664            fSetupFragPositionLocal = true;
665        }
666        this->write("sk_FragCoord");
667    }
668}
669
670void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
671    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
672        case SK_FRAGCOLOR_BUILTIN:
673            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
674                this->write("sk_FragColor");
675            } else {
676                this->write("gl_FragColor");
677            }
678            break;
679        case SK_FRAGCOORD_BUILTIN:
680            this->writeFragCoord();
681            break;
682        case SK_VERTEXID_BUILTIN:
683            this->write("gl_VertexID");
684            break;
685        case SK_INSTANCEID_BUILTIN:
686            this->write("gl_InstanceID");
687            break;
688        case SK_CLIPDISTANCE_BUILTIN:
689            this->write("gl_ClipDistance");
690            break;
691        case SK_IN_BUILTIN:
692            this->write("gl_in");
693            break;
694        case SK_INVOCATIONID_BUILTIN:
695            this->write("gl_InvocationID");
696            break;
697        default:
698            this->write(ref.fVariable.fName);
699    }
700}
701
702void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
703    this->writeExpression(*expr.fBase, kPostfix_Precedence);
704    this->write("[");
705    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
706    this->write("]");
707}
708
709bool is_sk_position(const FieldAccess& f) {
710    return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
711}
712
713void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
714    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
715        this->writeExpression(*f.fBase, kPostfix_Precedence);
716        this->write(".");
717    }
718    switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
719        case SK_CLIPDISTANCE_BUILTIN:
720            this->write("gl_ClipDistance");
721            break;
722        default:
723            StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
724            if (name == "sk_Position") {
725                this->write("gl_Position");
726            } else if (name == "sk_PointSize") {
727                this->write("gl_PointSize");
728            } else {
729                this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
730            }
731    }
732}
733
734void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
735    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
736    this->write(".");
737    for (int c : swizzle.fComponents) {
738        this->write(&("x\0y\0z\0w\0"[c * 2]));
739    }
740}
741
742GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
743    switch (op) {
744        case Token::STAR:         // fall through
745        case Token::SLASH:        // fall through
746        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
747        case Token::PLUS:         // fall through
748        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
749        case Token::SHL:          // fall through
750        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
751        case Token::LT:           // fall through
752        case Token::GT:           // fall through
753        case Token::LTEQ:         // fall through
754        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
755        case Token::EQEQ:         // fall through
756        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
757        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
758        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
759        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
760        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
761        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
762        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
763        case Token::EQ:           // fall through
764        case Token::PLUSEQ:       // fall through
765        case Token::MINUSEQ:      // fall through
766        case Token::STAREQ:       // fall through
767        case Token::SLASHEQ:      // fall through
768        case Token::PERCENTEQ:    // fall through
769        case Token::SHLEQ:        // fall through
770        case Token::SHREQ:        // fall through
771        case Token::LOGICALANDEQ: // fall through
772        case Token::LOGICALXOREQ: // fall through
773        case Token::LOGICALOREQ:  // fall through
774        case Token::BITWISEANDEQ: // fall through
775        case Token::BITWISEXOREQ: // fall through
776        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
777        case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
778        default: ABORT("unsupported binary operator");
779    }
780}
781
782void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
783                                              Precedence parentPrecedence) {
784    Precedence precedence = GetBinaryPrecedence(b.fOperator);
785    if (precedence >= parentPrecedence) {
786        this->write("(");
787    }
788    bool positionWorkaround = Compiler::IsAssignment(b.fOperator) &&
789                              Expression::kFieldAccess_Kind == b.fLeft->fKind &&
790                              is_sk_position((FieldAccess&) *b.fLeft) &&
791                              !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
792                              !fProgram.fSettings.fCaps->canUseFragCoord();
793    if (positionWorkaround) {
794        this->write("sk_FragCoord_Workaround = (");
795    }
796    this->writeExpression(*b.fLeft, precedence);
797    this->write(" ");
798    this->write(Compiler::OperatorName(b.fOperator));
799    this->write(" ");
800    this->writeExpression(*b.fRight, precedence);
801    if (positionWorkaround) {
802        this->write(")");
803    }
804    if (precedence >= parentPrecedence) {
805        this->write(")");
806    }
807}
808
809void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
810                                               Precedence parentPrecedence) {
811    if (kTernary_Precedence >= parentPrecedence) {
812        this->write("(");
813    }
814    this->writeExpression(*t.fTest, kTernary_Precedence);
815    this->write(" ? ");
816    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
817    this->write(" : ");
818    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
819    if (kTernary_Precedence >= parentPrecedence) {
820        this->write(")");
821    }
822}
823
824void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
825                                              Precedence parentPrecedence) {
826    if (kPrefix_Precedence >= parentPrecedence) {
827        this->write("(");
828    }
829    this->write(Compiler::OperatorName(p.fOperator));
830    this->writeExpression(*p.fOperand, kPrefix_Precedence);
831    if (kPrefix_Precedence >= parentPrecedence) {
832        this->write(")");
833    }
834}
835
836void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
837                                               Precedence parentPrecedence) {
838    if (kPostfix_Precedence >= parentPrecedence) {
839        this->write("(");
840    }
841    this->writeExpression(*p.fOperand, kPostfix_Precedence);
842    this->write(Compiler::OperatorName(p.fOperator));
843    if (kPostfix_Precedence >= parentPrecedence) {
844        this->write(")");
845    }
846}
847
848void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
849    this->write(b.fValue ? "true" : "false");
850}
851
852void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
853    if (i.fType == *fContext.fUInt_Type) {
854        this->write(to_string(i.fValue & 0xffffffff) + "u");
855    } else if (i.fType == *fContext.fUShort_Type) {
856        this->write(to_string(i.fValue & 0xffff) + "u");
857     } else {
858        this->write(to_string((int32_t) i.fValue));
859    }
860}
861
862void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
863    this->write(to_string(f.fValue));
864}
865
866void GLSLCodeGenerator::writeSetting(const Setting& s) {
867    ABORT("internal error; setting was not folded to a constant during compilation\n");
868}
869
870void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
871    this->writeTypePrecision(f.fDeclaration.fReturnType);
872    this->writeType(f.fDeclaration.fReturnType);
873    this->write(" " + f.fDeclaration.fName + "(");
874    const char* separator = "";
875    for (const auto& param : f.fDeclaration.fParameters) {
876        this->write(separator);
877        separator = ", ";
878        this->writeModifiers(param->fModifiers, false);
879        std::vector<int> sizes;
880        const Type* type = &param->fType;
881        while (type->kind() == Type::kArray_Kind) {
882            sizes.push_back(type->columns());
883            type = &type->componentType();
884        }
885        this->writeTypePrecision(*type);
886        this->writeType(*type);
887        this->write(" " + param->fName);
888        for (int s : sizes) {
889            if (s <= 0) {
890                this->write("[]");
891            } else {
892                this->write("[" + to_string(s) + "]");
893            }
894        }
895    }
896    this->writeLine(") {");
897
898    fFunctionHeader = "";
899    OutputStream* oldOut = fOut;
900    StringStream buffer;
901    fOut = &buffer;
902    fIndentation++;
903    this->writeStatements(((Block&) *f.fBody).fStatements);
904    fIndentation--;
905    this->writeLine("}");
906
907    fOut = oldOut;
908    this->write(fFunctionHeader);
909    this->write(buffer.str());
910}
911
912void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
913                                       bool globalContext) {
914    if (modifiers.fFlags & Modifiers::kFlat_Flag) {
915        this->write("flat ");
916    }
917    if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
918        this->write("noperspective ");
919    }
920    String layout = modifiers.fLayout.description();
921    if (layout.size()) {
922        this->write(layout + " ");
923    }
924    if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
925        this->write("readonly ");
926    }
927    if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
928        this->write("writeonly ");
929    }
930    if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
931        this->write("coherent ");
932    }
933    if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
934        this->write("volatile ");
935    }
936    if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
937        this->write("restrict ");
938    }
939    if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
940        (modifiers.fFlags & Modifiers::kOut_Flag)) {
941        this->write("inout ");
942    } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
943        if (globalContext &&
944            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
945            this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
946                                                              : "varying ");
947        } else {
948            this->write("in ");
949        }
950    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
951        if (globalContext &&
952            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
953            this->write("varying ");
954        } else {
955            this->write("out ");
956        }
957    }
958    if (modifiers.fFlags & Modifiers::kUniform_Flag) {
959        this->write("uniform ");
960    }
961    if (modifiers.fFlags & Modifiers::kConst_Flag) {
962        this->write("const ");
963    }
964    if (usesPrecisionModifiers()) {
965        if (modifiers.fFlags & Modifiers::kLowp_Flag) {
966            this->write("lowp ");
967        }
968        if (modifiers.fFlags & Modifiers::kMediump_Flag) {
969            this->write("mediump ");
970        }
971        if (modifiers.fFlags & Modifiers::kHighp_Flag) {
972            this->write("highp ");
973        }
974    }
975}
976
977void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
978    if (intf.fTypeName == "sk_PerVertex") {
979        return;
980    }
981    this->writeModifiers(intf.fVariable.fModifiers, true);
982    this->writeLine(intf.fTypeName + " {");
983    fIndentation++;
984    const Type* structType = &intf.fVariable.fType;
985    while (structType->kind() == Type::kArray_Kind) {
986        structType = &structType->componentType();
987    }
988    for (const auto& f : structType->fields()) {
989        this->writeModifiers(f.fModifiers, false);
990        this->writeTypePrecision(*f.fType);
991        this->writeType(*f.fType);
992        this->writeLine(" " + f.fName + ";");
993    }
994    fIndentation--;
995    this->write("}");
996    if (intf.fInstanceName.size()) {
997        this->write(" ");
998        this->write(intf.fInstanceName);
999        for (const auto& size : intf.fSizes) {
1000            this->write("[");
1001            if (size) {
1002                this->writeExpression(*size, kTopLevel_Precedence);
1003            }
1004            this->write("]");
1005        }
1006    }
1007    this->writeLine(";");
1008}
1009
1010void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1011    this->writeExpression(value, kTopLevel_Precedence);
1012}
1013
1014const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1015    if (usesPrecisionModifiers()) {
1016        switch (type.kind()) {
1017            case Type::kScalar_Kind:
1018                if (type == *fContext.fHalf_Type || type == *fContext.fShort_Type ||
1019                        type == *fContext.fUShort_Type) {
1020                    return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
1021                }
1022                if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1023                        type == *fContext.fUInt_Type) {
1024                    return "highp ";
1025                }
1026                return "";
1027            case Type::kVector_Kind: // fall through
1028            case Type::kMatrix_Kind:
1029                return this->getTypePrecision(type.componentType());
1030            default:
1031                break;
1032        }
1033    }
1034    return "";
1035}
1036
1037void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1038    this->write(this->getTypePrecision(type));
1039}
1040
1041void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
1042    if (!decl.fVars.size()) {
1043        return;
1044    }
1045    bool wroteType = false;
1046    for (const auto& stmt : decl.fVars) {
1047        VarDeclaration& var = (VarDeclaration&) *stmt;
1048        if (wroteType) {
1049            this->write(", ");
1050        } else {
1051            this->writeModifiers(var.fVar->fModifiers, global);
1052            this->writeTypePrecision(decl.fBaseType);
1053            this->writeType(decl.fBaseType);
1054            this->write(" ");
1055            wroteType = true;
1056        }
1057        this->write(var.fVar->fName);
1058        for (const auto& size : var.fSizes) {
1059            this->write("[");
1060            if (size) {
1061                this->writeExpression(*size, kTopLevel_Precedence);
1062            }
1063            this->write("]");
1064        }
1065        if (var.fValue) {
1066            this->write(" = ");
1067            this->writeVarInitializer(*var.fVar, *var.fValue);
1068        }
1069        if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
1070            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
1071                fHeader.writeText("#extension ");
1072                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
1073                fHeader.writeText(" : require\n");
1074            }
1075            fFoundImageDecl = true;
1076        }
1077    }
1078    if (wroteType) {
1079        this->write(";");
1080    }
1081}
1082
1083void GLSLCodeGenerator::writeStatement(const Statement& s) {
1084    switch (s.fKind) {
1085        case Statement::kBlock_Kind:
1086            this->writeBlock((Block&) s);
1087            break;
1088        case Statement::kExpression_Kind:
1089            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1090            this->write(";");
1091            break;
1092        case Statement::kReturn_Kind:
1093            this->writeReturnStatement((ReturnStatement&) s);
1094            break;
1095        case Statement::kVarDeclarations_Kind:
1096            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
1097            break;
1098        case Statement::kIf_Kind:
1099            this->writeIfStatement((IfStatement&) s);
1100            break;
1101        case Statement::kFor_Kind:
1102            this->writeForStatement((ForStatement&) s);
1103            break;
1104        case Statement::kWhile_Kind:
1105            this->writeWhileStatement((WhileStatement&) s);
1106            break;
1107        case Statement::kDo_Kind:
1108            this->writeDoStatement((DoStatement&) s);
1109            break;
1110        case Statement::kSwitch_Kind:
1111            this->writeSwitchStatement((SwitchStatement&) s);
1112            break;
1113        case Statement::kBreak_Kind:
1114            this->write("break;");
1115            break;
1116        case Statement::kContinue_Kind:
1117            this->write("continue;");
1118            break;
1119        case Statement::kDiscard_Kind:
1120            this->write("discard;");
1121            break;
1122        case Statement::kNop_Kind:
1123            this->write(";");
1124            break;
1125        default:
1126            ABORT("unsupported statement: %s", s.description().c_str());
1127    }
1128}
1129
1130void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1131    for (const auto& s : statements) {
1132        if (!s->isEmpty()) {
1133            this->writeStatement(*s);
1134            this->writeLine();
1135        }
1136    }
1137}
1138
1139void GLSLCodeGenerator::writeBlock(const Block& b) {
1140    this->writeLine("{");
1141    fIndentation++;
1142    this->writeStatements(b.fStatements);
1143    fIndentation--;
1144    this->write("}");
1145}
1146
1147void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1148    this->write("if (");
1149    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1150    this->write(") ");
1151    this->writeStatement(*stmt.fIfTrue);
1152    if (stmt.fIfFalse) {
1153        this->write(" else ");
1154        this->writeStatement(*stmt.fIfFalse);
1155    }
1156}
1157
1158void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1159    this->write("for (");
1160    if (f.fInitializer && !f.fInitializer->isEmpty()) {
1161        this->writeStatement(*f.fInitializer);
1162    } else {
1163        this->write("; ");
1164    }
1165    if (f.fTest) {
1166        this->writeExpression(*f.fTest, kTopLevel_Precedence);
1167    }
1168    this->write("; ");
1169    if (f.fNext) {
1170        this->writeExpression(*f.fNext, kTopLevel_Precedence);
1171    }
1172    this->write(") ");
1173    this->writeStatement(*f.fStatement);
1174}
1175
1176void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1177    this->write("while (");
1178    this->writeExpression(*w.fTest, kTopLevel_Precedence);
1179    this->write(") ");
1180    this->writeStatement(*w.fStatement);
1181}
1182
1183void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1184    this->write("do ");
1185    this->writeStatement(*d.fStatement);
1186    this->write(" while (");
1187    this->writeExpression(*d.fTest, kTopLevel_Precedence);
1188    this->write(");");
1189}
1190
1191void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1192    this->write("switch (");
1193    this->writeExpression(*s.fValue, kTopLevel_Precedence);
1194    this->writeLine(") {");
1195    fIndentation++;
1196    for (const auto& c : s.fCases) {
1197        if (c->fValue) {
1198            this->write("case ");
1199            this->writeExpression(*c->fValue, kTopLevel_Precedence);
1200            this->writeLine(":");
1201        } else {
1202            this->writeLine("default:");
1203        }
1204        fIndentation++;
1205        for (const auto& stmt : c->fStatements) {
1206            this->writeStatement(*stmt);
1207            this->writeLine();
1208        }
1209        fIndentation--;
1210    }
1211    fIndentation--;
1212    this->write("}");
1213}
1214
1215void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1216    this->write("return");
1217    if (r.fExpression) {
1218        this->write(" ");
1219        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1220    }
1221    this->write(";");
1222}
1223
1224void GLSLCodeGenerator::writeHeader() {
1225    this->write(fProgram.fSettings.fCaps->versionDeclString());
1226    this->writeLine();
1227    for (const auto& e : fProgram.fElements) {
1228        if (e->fKind == ProgramElement::kExtension_Kind) {
1229            this->writeExtension((Extension&) *e);
1230        }
1231    }
1232    if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1233        Layout layout;
1234        switch (fProgram.fKind) {
1235            case Program::kVertex_Kind: {
1236                Modifiers modifiers(layout, Modifiers::kOut_Flag | Modifiers::kHighp_Flag);
1237                this->writeModifiers(modifiers, true);
1238                this->write("vec4 sk_FragCoord_Workaround;\n");
1239                break;
1240            }
1241            case Program::kFragment_Kind: {
1242                Modifiers modifiers(layout, Modifiers::kIn_Flag | Modifiers::kHighp_Flag);
1243                this->writeModifiers(modifiers, true);
1244                this->write("vec4 sk_FragCoord_Workaround;\n");
1245                break;
1246            }
1247            default:
1248                break;
1249        }
1250    }
1251}
1252
1253void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1254    switch (e.fKind) {
1255        case ProgramElement::kExtension_Kind:
1256            break;
1257        case ProgramElement::kVar_Kind: {
1258            VarDeclarations& decl = (VarDeclarations&) e;
1259            if (decl.fVars.size() > 0) {
1260                int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
1261                if (builtin == -1) {
1262                    // normal var
1263                    this->writeVarDeclarations(decl, true);
1264                    this->writeLine();
1265                } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1266                           fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
1267                    if (fProgram.fSettings.fFragColorIsInOut) {
1268                        this->write("inout ");
1269                    } else {
1270                        this->write("out ");
1271                    }
1272                    if (usesPrecisionModifiers()) {
1273                        this->write("mediump ");
1274                    }
1275                    this->writeLine("vec4 sk_FragColor;");
1276                }
1277            }
1278            break;
1279        }
1280        case ProgramElement::kInterfaceBlock_Kind:
1281            this->writeInterfaceBlock((InterfaceBlock&) e);
1282            break;
1283        case ProgramElement::kFunction_Kind:
1284            this->writeFunction((FunctionDefinition&) e);
1285            break;
1286        case ProgramElement::kModifiers_Kind: {
1287            const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1288            if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1289                if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
1290                    fHeader.writeText("#extension ");
1291                    fHeader.writeText(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
1292                    fHeader.writeText(" : require\n");
1293                }
1294                fFoundGSInvocations = true;
1295            }
1296            this->writeModifiers(modifiers, true);
1297            this->writeLine(";");
1298            break;
1299        }
1300        case ProgramElement::kEnum_Kind:
1301            break;
1302        default:
1303            printf("%s\n", e.description().c_str());
1304            ABORT("unsupported program element");
1305    }
1306}
1307
1308bool GLSLCodeGenerator::generateCode() {
1309    OutputStream* rawOut = fOut;
1310    fOut = &fHeader;
1311    fProgramKind = fProgram.fKind;
1312    this->writeHeader();
1313    if (Program::kGeometry_Kind == fProgramKind &&
1314        fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
1315        fHeader.writeText("#extension ");
1316        fHeader.writeText(fProgram.fSettings.fCaps->geometryShaderExtensionString());
1317        fHeader.writeText(" : require\n");
1318    }
1319    StringStream body;
1320    fOut = &body;
1321    for (const auto& e : fProgram.fElements) {
1322        this->writeProgramElement(*e);
1323    }
1324    fOut = rawOut;
1325
1326    write_stringstream(fHeader, *rawOut);
1327    if (this->usesPrecisionModifiers()) {
1328        this->writeLine("precision mediump float;");
1329    }
1330    write_stringstream(fExtraFunctions, *rawOut);
1331    write_stringstream(body, *rawOut);
1332    return true;
1333}
1334
1335}
1336