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    if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
509        const char* dim = "";
510        bool proj = false;
511        switch (c.fArguments[0]->fType.dimensions()) {
512            case SpvDim1D:
513                dim = "1D";
514                if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
515                    proj = false;
516                } else {
517                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
518                    proj = true;
519                }
520                break;
521            case SpvDim2D:
522                dim = "2D";
523                if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
524                    proj = false;
525                } else {
526                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
527                    proj = true;
528                }
529                break;
530            case SpvDim3D:
531                dim = "3D";
532                if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
533                    proj = false;
534                } else {
535                    ASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
536                    proj = true;
537                }
538                break;
539            case SpvDimCube:
540                dim = "Cube";
541                proj = false;
542                break;
543            case SpvDimRect:
544                dim = "Rect";
545                proj = false;
546                break;
547            case SpvDimBuffer:
548                ASSERT(false); // doesn't exist
549                dim = "Buffer";
550                proj = false;
551                break;
552            case SpvDimSubpassData:
553                ASSERT(false); // doesn't exist
554                dim = "SubpassData";
555                proj = false;
556                break;
557        }
558        this->write("texture");
559        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
560            this->write(dim);
561        }
562        if (proj) {
563            this->write("Proj");
564        }
565
566    } else {
567        this->write(c.fFunction.fName);
568    }
569    this->write("(");
570    const char* separator = "";
571    for (const auto& arg : c.fArguments) {
572        this->write(separator);
573        separator = ", ";
574        this->writeExpression(*arg, kSequence_Precedence);
575    }
576    this->write(")");
577}
578
579void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
580    if (c.fArguments.size() == 1 &&
581        this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
582        // in cases like half(float), they're different types as far as SkSL is concerned but the
583        // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
584        // out the inner expression here.
585        this->writeExpression(*c.fArguments[0], parentPrecedence);
586        return;
587    }
588    this->writeType(c.fType);
589    this->write("(");
590    const char* separator = "";
591    for (const auto& arg : c.fArguments) {
592        this->write(separator);
593        separator = ", ";
594        this->writeExpression(*arg, kSequence_Precedence);
595    }
596    this->write(")");
597}
598
599void GLSLCodeGenerator::writeFragCoord() {
600    if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
601        if (!fSetupFragCoordWorkaround) {
602            const char* precision = usesPrecisionModifiers() ? "highp " : "";
603            fFunctionHeader += precision;
604            fFunctionHeader += "    float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
605            fFunctionHeader += precision;
606            fFunctionHeader += "    vec4 sk_FragCoord_Resolved = "
607                "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
608            // Ensure that we get exact .5 values for x and y.
609            fFunctionHeader += "    sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
610                               "vec2(.5);\n";
611            fSetupFragCoordWorkaround = true;
612        }
613        this->write("sk_FragCoord_Resolved");
614        return;
615    }
616
617    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
618    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
619    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
620    if (!fProgram.fSettings.fFlipY) {
621        this->write("gl_FragCoord");
622    } else if (const char* extension =
623               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
624        if (!fSetupFragPositionGlobal) {
625            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
626                fHeader.writeText("#extension ");
627                fHeader.writeText(extension);
628                fHeader.writeText(" : require\n");
629            }
630            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
631            fSetupFragPositionGlobal = true;
632        }
633        this->write("gl_FragCoord");
634    } else {
635        if (!fSetupFragPositionGlobal) {
636            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
637            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
638            // depending on the surrounding code, accessing .xy with a uniform involved can
639            // do the same thing. Copying gl_FragCoord.xy into a temp float2 beforehand
640            // (and only accessing .xy) seems to "fix" things.
641            const char* precision = usesPrecisionModifiers() ? "highp " : "";
642            fHeader.writeText("uniform ");
643            fHeader.writeText(precision);
644            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
645            fSetupFragPositionGlobal = true;
646        }
647        if (!fSetupFragPositionLocal) {
648            const char* precision = usesPrecisionModifiers() ? "highp " : "";
649            fFunctionHeader += precision;
650            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
651            fFunctionHeader += precision;
652            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
653                               " - _sktmpCoord.y, 1.0, 1.0);\n";
654            fSetupFragPositionLocal = true;
655        }
656        this->write("sk_FragCoord");
657    }
658}
659
660void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
661    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
662        case SK_FRAGCOLOR_BUILTIN:
663            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
664                this->write("sk_FragColor");
665            } else {
666                this->write("gl_FragColor");
667            }
668            break;
669        case SK_FRAGCOORD_BUILTIN:
670            this->writeFragCoord();
671            break;
672        case SK_VERTEXID_BUILTIN:
673            this->write("gl_VertexID");
674            break;
675        case SK_INSTANCEID_BUILTIN:
676            this->write("gl_InstanceID");
677            break;
678        case SK_CLIPDISTANCE_BUILTIN:
679            this->write("gl_ClipDistance");
680            break;
681        case SK_IN_BUILTIN:
682            this->write("gl_in");
683            break;
684        case SK_INVOCATIONID_BUILTIN:
685            this->write("gl_InvocationID");
686            break;
687        default:
688            this->write(ref.fVariable.fName);
689    }
690}
691
692void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
693    this->writeExpression(*expr.fBase, kPostfix_Precedence);
694    this->write("[");
695    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
696    this->write("]");
697}
698
699bool is_sk_position(const FieldAccess& f) {
700    return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
701}
702
703void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
704    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
705        this->writeExpression(*f.fBase, kPostfix_Precedence);
706        this->write(".");
707    }
708    switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
709        case SK_CLIPDISTANCE_BUILTIN:
710            this->write("gl_ClipDistance");
711            break;
712        default:
713            StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
714            if (name == "sk_Position") {
715                this->write("gl_Position");
716            } else if (name == "sk_PointSize") {
717                this->write("gl_PointSize");
718            } else {
719                this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
720            }
721    }
722}
723
724void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
725    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
726    this->write(".");
727    for (int c : swizzle.fComponents) {
728        this->write(&("x\0y\0z\0w\0"[c * 2]));
729    }
730}
731
732GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
733    switch (op) {
734        case Token::STAR:         // fall through
735        case Token::SLASH:        // fall through
736        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
737        case Token::PLUS:         // fall through
738        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
739        case Token::SHL:          // fall through
740        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
741        case Token::LT:           // fall through
742        case Token::GT:           // fall through
743        case Token::LTEQ:         // fall through
744        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
745        case Token::EQEQ:         // fall through
746        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
747        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
748        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
749        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
750        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
751        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
752        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
753        case Token::EQ:           // fall through
754        case Token::PLUSEQ:       // fall through
755        case Token::MINUSEQ:      // fall through
756        case Token::STAREQ:       // fall through
757        case Token::SLASHEQ:      // fall through
758        case Token::PERCENTEQ:    // fall through
759        case Token::SHLEQ:        // fall through
760        case Token::SHREQ:        // fall through
761        case Token::LOGICALANDEQ: // fall through
762        case Token::LOGICALXOREQ: // fall through
763        case Token::LOGICALOREQ:  // fall through
764        case Token::BITWISEANDEQ: // fall through
765        case Token::BITWISEXOREQ: // fall through
766        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
767        case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
768        default: ABORT("unsupported binary operator");
769    }
770}
771
772void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
773                                              Precedence parentPrecedence) {
774    Precedence precedence = GetBinaryPrecedence(b.fOperator);
775    if (precedence >= parentPrecedence) {
776        this->write("(");
777    }
778    bool positionWorkaround = Compiler::IsAssignment(b.fOperator) &&
779                              Expression::kFieldAccess_Kind == b.fLeft->fKind &&
780                              is_sk_position((FieldAccess&) *b.fLeft) &&
781                              !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
782                              !fProgram.fSettings.fCaps->canUseFragCoord();
783    if (positionWorkaround) {
784        this->write("sk_FragCoord_Workaround = (");
785    }
786    this->writeExpression(*b.fLeft, precedence);
787    this->write(" ");
788    this->write(Compiler::OperatorName(b.fOperator));
789    this->write(" ");
790    this->writeExpression(*b.fRight, precedence);
791    if (positionWorkaround) {
792        this->write(")");
793    }
794    if (precedence >= parentPrecedence) {
795        this->write(")");
796    }
797}
798
799void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
800                                               Precedence parentPrecedence) {
801    if (kTernary_Precedence >= parentPrecedence) {
802        this->write("(");
803    }
804    this->writeExpression(*t.fTest, kTernary_Precedence);
805    this->write(" ? ");
806    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
807    this->write(" : ");
808    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
809    if (kTernary_Precedence >= parentPrecedence) {
810        this->write(")");
811    }
812}
813
814void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
815                                              Precedence parentPrecedence) {
816    if (kPrefix_Precedence >= parentPrecedence) {
817        this->write("(");
818    }
819    this->write(Compiler::OperatorName(p.fOperator));
820    this->writeExpression(*p.fOperand, kPrefix_Precedence);
821    if (kPrefix_Precedence >= parentPrecedence) {
822        this->write(")");
823    }
824}
825
826void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
827                                               Precedence parentPrecedence) {
828    if (kPostfix_Precedence >= parentPrecedence) {
829        this->write("(");
830    }
831    this->writeExpression(*p.fOperand, kPostfix_Precedence);
832    this->write(Compiler::OperatorName(p.fOperator));
833    if (kPostfix_Precedence >= parentPrecedence) {
834        this->write(")");
835    }
836}
837
838void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
839    this->write(b.fValue ? "true" : "false");
840}
841
842void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
843    if (i.fType == *fContext.fUInt_Type) {
844        this->write(to_string(i.fValue & 0xffffffff) + "u");
845    } else if (i.fType == *fContext.fUShort_Type) {
846        this->write(to_string(i.fValue & 0xffff) + "u");
847     } else {
848        this->write(to_string((int32_t) i.fValue));
849    }
850}
851
852void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
853    this->write(to_string(f.fValue));
854}
855
856void GLSLCodeGenerator::writeSetting(const Setting& s) {
857    ABORT("internal error; setting was not folded to a constant during compilation\n");
858}
859
860void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
861    this->writeTypePrecision(f.fDeclaration.fReturnType);
862    this->writeType(f.fDeclaration.fReturnType);
863    this->write(" " + f.fDeclaration.fName + "(");
864    const char* separator = "";
865    for (const auto& param : f.fDeclaration.fParameters) {
866        this->write(separator);
867        separator = ", ";
868        this->writeModifiers(param->fModifiers, false);
869        std::vector<int> sizes;
870        const Type* type = &param->fType;
871        while (type->kind() == Type::kArray_Kind) {
872            sizes.push_back(type->columns());
873            type = &type->componentType();
874        }
875        this->writeTypePrecision(*type);
876        this->writeType(*type);
877        this->write(" " + param->fName);
878        for (int s : sizes) {
879            if (s <= 0) {
880                this->write("[]");
881            } else {
882                this->write("[" + to_string(s) + "]");
883            }
884        }
885    }
886    this->writeLine(") {");
887
888    fFunctionHeader = "";
889    OutputStream* oldOut = fOut;
890    StringStream buffer;
891    fOut = &buffer;
892    fIndentation++;
893    this->writeStatements(((Block&) *f.fBody).fStatements);
894    fIndentation--;
895    this->writeLine("}");
896
897    fOut = oldOut;
898    this->write(fFunctionHeader);
899    this->write(buffer.str());
900}
901
902void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
903                                       bool globalContext) {
904    if (modifiers.fFlags & Modifiers::kFlat_Flag) {
905        this->write("flat ");
906    }
907    if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
908        this->write("noperspective ");
909    }
910    String layout = modifiers.fLayout.description();
911    if (layout.size()) {
912        this->write(layout + " ");
913    }
914    if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
915        this->write("readonly ");
916    }
917    if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
918        this->write("writeonly ");
919    }
920    if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
921        this->write("coherent ");
922    }
923    if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
924        this->write("volatile ");
925    }
926    if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
927        this->write("restrict ");
928    }
929    if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
930        (modifiers.fFlags & Modifiers::kOut_Flag)) {
931        this->write("inout ");
932    } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
933        if (globalContext &&
934            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
935            this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
936                                                              : "varying ");
937        } else {
938            this->write("in ");
939        }
940    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
941        if (globalContext &&
942            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
943            this->write("varying ");
944        } else {
945            this->write("out ");
946        }
947    }
948    if (modifiers.fFlags & Modifiers::kUniform_Flag) {
949        this->write("uniform ");
950    }
951    if (modifiers.fFlags & Modifiers::kConst_Flag) {
952        this->write("const ");
953    }
954    if (usesPrecisionModifiers()) {
955        if (modifiers.fFlags & Modifiers::kLowp_Flag) {
956            this->write("lowp ");
957        }
958        if (modifiers.fFlags & Modifiers::kMediump_Flag) {
959            this->write("mediump ");
960        }
961        if (modifiers.fFlags & Modifiers::kHighp_Flag) {
962            this->write("highp ");
963        }
964    }
965}
966
967void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
968    if (intf.fTypeName == "sk_PerVertex") {
969        return;
970    }
971    this->writeModifiers(intf.fVariable.fModifiers, true);
972    this->writeLine(intf.fTypeName + " {");
973    fIndentation++;
974    const Type* structType = &intf.fVariable.fType;
975    while (structType->kind() == Type::kArray_Kind) {
976        structType = &structType->componentType();
977    }
978    for (const auto& f : structType->fields()) {
979        this->writeModifiers(f.fModifiers, false);
980        this->writeTypePrecision(*f.fType);
981        this->writeType(*f.fType);
982        this->writeLine(" " + f.fName + ";");
983    }
984    fIndentation--;
985    this->write("}");
986    if (intf.fInstanceName.size()) {
987        this->write(" ");
988        this->write(intf.fInstanceName);
989        for (const auto& size : intf.fSizes) {
990            this->write("[");
991            if (size) {
992                this->writeExpression(*size, kTopLevel_Precedence);
993            }
994            this->write("]");
995        }
996    }
997    this->writeLine(";");
998}
999
1000void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1001    this->writeExpression(value, kTopLevel_Precedence);
1002}
1003
1004const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1005    if (usesPrecisionModifiers()) {
1006        switch (type.kind()) {
1007            case Type::kScalar_Kind:
1008                if (type == *fContext.fHalf_Type || type == *fContext.fShort_Type ||
1009                        type == *fContext.fUShort_Type) {
1010                    return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
1011                }
1012                if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1013                        type == *fContext.fUInt_Type) {
1014                    return "highp ";
1015                }
1016                return "";
1017            case Type::kVector_Kind: // fall through
1018            case Type::kMatrix_Kind:
1019                return this->getTypePrecision(type.componentType());
1020            default:
1021                break;
1022        }
1023    }
1024    return "";
1025}
1026
1027void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1028    this->write(this->getTypePrecision(type));
1029}
1030
1031void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
1032    if (!decl.fVars.size()) {
1033        return;
1034    }
1035    bool wroteType = false;
1036    for (const auto& stmt : decl.fVars) {
1037        VarDeclaration& var = (VarDeclaration&) *stmt;
1038        if (wroteType) {
1039            this->write(", ");
1040        } else {
1041            this->writeModifiers(var.fVar->fModifiers, global);
1042            this->writeTypePrecision(decl.fBaseType);
1043            this->writeType(decl.fBaseType);
1044            this->write(" ");
1045            wroteType = true;
1046        }
1047        this->write(var.fVar->fName);
1048        for (const auto& size : var.fSizes) {
1049            this->write("[");
1050            if (size) {
1051                this->writeExpression(*size, kTopLevel_Precedence);
1052            }
1053            this->write("]");
1054        }
1055        if (var.fValue) {
1056            this->write(" = ");
1057            this->writeVarInitializer(*var.fVar, *var.fValue);
1058        }
1059        if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
1060            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
1061                fHeader.writeText("#extension ");
1062                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
1063                fHeader.writeText(" : require\n");
1064            }
1065            fFoundImageDecl = true;
1066        }
1067    }
1068    if (wroteType) {
1069        this->write(";");
1070    }
1071}
1072
1073void GLSLCodeGenerator::writeStatement(const Statement& s) {
1074    switch (s.fKind) {
1075        case Statement::kBlock_Kind:
1076            this->writeBlock((Block&) s);
1077            break;
1078        case Statement::kExpression_Kind:
1079            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1080            this->write(";");
1081            break;
1082        case Statement::kReturn_Kind:
1083            this->writeReturnStatement((ReturnStatement&) s);
1084            break;
1085        case Statement::kVarDeclarations_Kind:
1086            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
1087            break;
1088        case Statement::kIf_Kind:
1089            this->writeIfStatement((IfStatement&) s);
1090            break;
1091        case Statement::kFor_Kind:
1092            this->writeForStatement((ForStatement&) s);
1093            break;
1094        case Statement::kWhile_Kind:
1095            this->writeWhileStatement((WhileStatement&) s);
1096            break;
1097        case Statement::kDo_Kind:
1098            this->writeDoStatement((DoStatement&) s);
1099            break;
1100        case Statement::kSwitch_Kind:
1101            this->writeSwitchStatement((SwitchStatement&) s);
1102            break;
1103        case Statement::kBreak_Kind:
1104            this->write("break;");
1105            break;
1106        case Statement::kContinue_Kind:
1107            this->write("continue;");
1108            break;
1109        case Statement::kDiscard_Kind:
1110            this->write("discard;");
1111            break;
1112        case Statement::kNop_Kind:
1113            this->write(";");
1114            break;
1115        default:
1116            ABORT("unsupported statement: %s", s.description().c_str());
1117    }
1118}
1119
1120void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1121    for (const auto& s : statements) {
1122        if (!s->isEmpty()) {
1123            this->writeStatement(*s);
1124            this->writeLine();
1125        }
1126    }
1127}
1128
1129void GLSLCodeGenerator::writeBlock(const Block& b) {
1130    this->writeLine("{");
1131    fIndentation++;
1132    this->writeStatements(b.fStatements);
1133    fIndentation--;
1134    this->write("}");
1135}
1136
1137void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1138    this->write("if (");
1139    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1140    this->write(") ");
1141    this->writeStatement(*stmt.fIfTrue);
1142    if (stmt.fIfFalse) {
1143        this->write(" else ");
1144        this->writeStatement(*stmt.fIfFalse);
1145    }
1146}
1147
1148void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1149    this->write("for (");
1150    if (f.fInitializer && !f.fInitializer->isEmpty()) {
1151        this->writeStatement(*f.fInitializer);
1152    } else {
1153        this->write("; ");
1154    }
1155    if (f.fTest) {
1156        this->writeExpression(*f.fTest, kTopLevel_Precedence);
1157    }
1158    this->write("; ");
1159    if (f.fNext) {
1160        this->writeExpression(*f.fNext, kTopLevel_Precedence);
1161    }
1162    this->write(") ");
1163    this->writeStatement(*f.fStatement);
1164}
1165
1166void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1167    this->write("while (");
1168    this->writeExpression(*w.fTest, kTopLevel_Precedence);
1169    this->write(") ");
1170    this->writeStatement(*w.fStatement);
1171}
1172
1173void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1174    this->write("do ");
1175    this->writeStatement(*d.fStatement);
1176    this->write(" while (");
1177    this->writeExpression(*d.fTest, kTopLevel_Precedence);
1178    this->write(");");
1179}
1180
1181void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1182    this->write("switch (");
1183    this->writeExpression(*s.fValue, kTopLevel_Precedence);
1184    this->writeLine(") {");
1185    fIndentation++;
1186    for (const auto& c : s.fCases) {
1187        if (c->fValue) {
1188            this->write("case ");
1189            this->writeExpression(*c->fValue, kTopLevel_Precedence);
1190            this->writeLine(":");
1191        } else {
1192            this->writeLine("default:");
1193        }
1194        fIndentation++;
1195        for (const auto& stmt : c->fStatements) {
1196            this->writeStatement(*stmt);
1197            this->writeLine();
1198        }
1199        fIndentation--;
1200    }
1201    fIndentation--;
1202    this->write("}");
1203}
1204
1205void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1206    this->write("return");
1207    if (r.fExpression) {
1208        this->write(" ");
1209        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1210    }
1211    this->write(";");
1212}
1213
1214void GLSLCodeGenerator::writeHeader() {
1215    this->write(fProgram.fSettings.fCaps->versionDeclString());
1216    this->writeLine();
1217    for (const auto& e : fProgram.fElements) {
1218        if (e->fKind == ProgramElement::kExtension_Kind) {
1219            this->writeExtension((Extension&) *e);
1220        }
1221    }
1222    if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1223        Layout layout;
1224        switch (fProgram.fKind) {
1225            case Program::kVertex_Kind: {
1226                Modifiers modifiers(layout, Modifiers::kOut_Flag | Modifiers::kHighp_Flag);
1227                this->writeModifiers(modifiers, true);
1228                this->write("vec4 sk_FragCoord_Workaround;\n");
1229                break;
1230            }
1231            case Program::kFragment_Kind: {
1232                Modifiers modifiers(layout, Modifiers::kIn_Flag | Modifiers::kHighp_Flag);
1233                this->writeModifiers(modifiers, true);
1234                this->write("vec4 sk_FragCoord_Workaround;\n");
1235                break;
1236            }
1237            default:
1238                break;
1239        }
1240    }
1241}
1242
1243void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1244    switch (e.fKind) {
1245        case ProgramElement::kExtension_Kind:
1246            break;
1247        case ProgramElement::kVar_Kind: {
1248            VarDeclarations& decl = (VarDeclarations&) e;
1249            if (decl.fVars.size() > 0) {
1250                int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
1251                if (builtin == -1) {
1252                    // normal var
1253                    this->writeVarDeclarations(decl, true);
1254                    this->writeLine();
1255                } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1256                           fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
1257                    if (fProgram.fSettings.fFragColorIsInOut) {
1258                        this->write("inout ");
1259                    } else {
1260                        this->write("out ");
1261                    }
1262                    if (usesPrecisionModifiers()) {
1263                        this->write("mediump ");
1264                    }
1265                    this->writeLine("vec4 sk_FragColor;");
1266                }
1267            }
1268            break;
1269        }
1270        case ProgramElement::kInterfaceBlock_Kind:
1271            this->writeInterfaceBlock((InterfaceBlock&) e);
1272            break;
1273        case ProgramElement::kFunction_Kind:
1274            this->writeFunction((FunctionDefinition&) e);
1275            break;
1276        case ProgramElement::kModifiers_Kind: {
1277            const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1278            if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1279                if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
1280                    fHeader.writeText("#extension ");
1281                    fHeader.writeText(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
1282                    fHeader.writeText(" : require\n");
1283                }
1284                fFoundGSInvocations = true;
1285            }
1286            this->writeModifiers(modifiers, true);
1287            this->writeLine(";");
1288            break;
1289        }
1290        case ProgramElement::kEnum_Kind:
1291            break;
1292        default:
1293            printf("%s\n", e.description().c_str());
1294            ABORT("unsupported program element");
1295    }
1296}
1297
1298bool GLSLCodeGenerator::generateCode() {
1299    OutputStream* rawOut = fOut;
1300    fOut = &fHeader;
1301    fProgramKind = fProgram.fKind;
1302    this->writeHeader();
1303    if (Program::kGeometry_Kind == fProgramKind &&
1304        fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
1305        fHeader.writeText("#extension ");
1306        fHeader.writeText(fProgram.fSettings.fCaps->geometryShaderExtensionString());
1307        fHeader.writeText(" : require\n");
1308    }
1309    StringStream body;
1310    fOut = &body;
1311    for (const auto& e : fProgram.fElements) {
1312        this->writeProgramElement(*e);
1313    }
1314    fOut = rawOut;
1315
1316    write_stringstream(fHeader, *rawOut);
1317    if (this->usesPrecisionModifiers()) {
1318        this->writeLine("precision mediump float;");
1319    }
1320    write_stringstream(fExtraFunctions, *rawOut);
1321    write_stringstream(body, *rawOut);
1322    return true;
1323}
1324
1325}
1326