1f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas/*
2f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas * Copyright 2016 Google Inc.
3f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas *
4f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas * Use of this source code is governed by a BSD-style license that can be
5f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas * found in the LICENSE file.
6f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas */
764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel
8f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "SkSLGLSLCodeGenerator.h"
9f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
10f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "string.h"
11f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
12f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "GLSL.std.450.h"
13f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
14941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas#include "SkSLCompiler.h"
15f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLExpressionStatement.h"
16f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLExtension.h"
17f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLIndexExpression.h"
185961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#include "ir/SkSLModifiersDeclaration.h"
19f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLVariableReference.h"
20f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
21f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasnamespace SkSL {
22f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
23f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::write(const char* s) {
24f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (s[0] == 0) {
25f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        return;
26f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
27f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (fAtLineStart) {
28f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (int i = 0; i < fIndentation; i++) {
299e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            fOut->writeText("    ");
30f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
31f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fOut->writeText(s);
33f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fAtLineStart = false;
34f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
35f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
36f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeLine(const char* s) {
37f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(s);
389e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fOut->writeText("\n");
39f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fAtLineStart = true;
40f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
41f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
429e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid GLSLCodeGenerator::write(const SkString& s) {
43f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(s.c_str());
44f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
45f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
469e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholasvoid GLSLCodeGenerator::writeLine(const SkString& s) {
47f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine(s.c_str());
48f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
49f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
50f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeLine() {
51f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("");
52f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
53f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
54f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeExtension(const Extension& ext) {
55f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("#extension " + ext.fName + " : enable");
56f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
57f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
58f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeType(const Type& type) {
59f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (type.kind() == Type::kStruct_Kind) {
60f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (const Type* search : fWrittenStructs) {
61f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            if (*search == type) {
62f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                // already written
63f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                this->write(type.name());
64f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                return;
65f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            }
66f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
67f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fWrittenStructs.push_back(&type);
68f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeLine("struct " + type.name() + " {");
69f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fIndentation++;
70f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (const auto& f : type.fields()) {
715961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeModifiers(f.fModifiers, false);
72f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            // sizes (which must be static in structs) are part of the type name here
730730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas            this->writeType(*f.fType);
74f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeLine(" " + f.fName + ";");
75f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
76f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fIndentation--;
7719671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        this->write("}");
78f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    } else {
79f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(type.name());
80f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
81f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
82f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
83f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
84f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (expr.fKind) {
85f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kBinary_Kind:
86f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
87f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
88f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kBoolLiteral_Kind:
89f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBoolLiteral((BoolLiteral&) expr);
90f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
91f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kConstructor_Kind:
92f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeConstructor((Constructor&) expr);
93f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
94f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kIntLiteral_Kind:
95f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIntLiteral((IntLiteral&) expr);
96f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
97f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFieldAccess_Kind:
98f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFieldAccess(((FieldAccess&) expr));
99f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
100f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFloatLiteral_Kind:
101f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFloatLiteral(((FloatLiteral&) expr));
102f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
103f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFunctionCall_Kind:
104f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFunctionCall((FunctionCall&) expr);
105f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
106f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kPrefix_Kind:
107f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
108f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
109f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kPostfix_Kind:
110f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
111f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
112f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kSwizzle_Kind:
113f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeSwizzle((Swizzle&) expr);
114f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
115f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kVariableReference_Kind:
116f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeVariableReference((VariableReference&) expr);
117f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
118f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kTernary_Kind:
119f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
120f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
121f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kIndex_Kind:
122f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIndexExpression((IndexExpression&) expr);
123f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
124f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default:
125f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            ABORT("unsupported expression: %s", expr.description().c_str());
126f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
127f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
128f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
1295961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasstatic bool is_abs(Expression& expr) {
1305961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (expr.fKind != Expression::kFunctionCall_Kind) {
1315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        return false;
1325961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
1335961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    return ((FunctionCall&) expr).fFunction.fName == "abs";
1345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas}
1355961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
136941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
1375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas// Tegra3 compiler bug.
1385961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasvoid GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
139941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
1409e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
1419e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
1425961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->fFunctionHeader += "    " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
1435961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->fFunctionHeader += "    " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
1445961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write("((" + tmpVar1 + " = ");
1455961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeExpression(absExpr, kTopLevel_Precedence);
1465961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(") < (" + tmpVar2 + " = ");
1475961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeExpression(otherExpr, kAssignment_Precedence);
1485961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
1495961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas}
1505961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
151f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
152941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
153941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin) {
1545961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        ASSERT(c.fArguments.size() == 2);
1555961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (is_abs(*c.fArguments[0])) {
1565961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
1575961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            return;
1585961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
1595961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (is_abs(*c.fArguments[1])) {
1605961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
1615961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            // ever end up mattering, but it's worth calling out.
1625961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
1635961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            return;
1645961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
1655961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
166941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
167941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fName == "atan" &&
168941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
169ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas        c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
170ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
171ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        if (p.fOperator == Token::MINUS) {
172ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write("atan(");
173ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->writeExpression(*c.fArguments[0], kSequence_Precedence);
174ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write(", -1.0 * ");
175ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
176ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write(")");
177ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            return;
178ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        }
179ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas    }
180941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
181941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
182941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
1839e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        fHeader.writeText("#extension ");
184941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
1859e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        fHeader.writeText(" : require\n");
186ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas        fFoundDerivatives = true;
187ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    }
1882b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
1892b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        const char* dim = "";
1902b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        bool proj = false;
1912b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        switch (c.fArguments[0]->fType.dimensions()) {
1922b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim1D:
1932b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "1D";
1942b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
1952b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
1962b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
1972b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
1982b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
1992b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2002b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2012b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim2D:
2022b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "2D";
2032b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
2042b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
2052b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
2062b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
2072b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
2082b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2092b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2102b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim3D:
2112b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "3D";
2122b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
2132b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
2142b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
2152b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec4_Type);
2162b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
2172b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2182b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2192b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimCube:
2202b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Cube";
2212b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2222b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2232b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimRect:
2242b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Rect";
2252b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2262b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2272b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimBuffer:
2282b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                ASSERT(false); // doesn't exist
2292b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Buffer";
2302b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2312b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2322b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimSubpassData:
2332b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                ASSERT(false); // doesn't exist
2342b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "SubpassData";
2352b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2362b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2372b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2382b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        this->write("texture");
239941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
2402b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            this->write(dim);
2412b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2422b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        if (proj) {
2432b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            this->write("Proj");
2442b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2452b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas
2462b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    } else {
2472b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        this->write(c.fFunction.fName);
2482b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    }
2492b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    this->write("(");
250f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
251f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& arg : c.fArguments) {
252f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
253f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
254f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*arg, kSequence_Precedence);
255f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
256f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(")");
257f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
258f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
259f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeConstructor(const Constructor& c) {
260f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(c.fType.name() + "(");
261f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
262f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& arg : c.fArguments) {
263f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
264f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
265f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*arg, kSequence_Precedence);
266f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
267f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(")");
268f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
269f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
270941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasvoid GLSLCodeGenerator::writeFragCoord() {
271941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
272941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
273941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
274941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fProgram.fSettings.fFlipY) {
275941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("gl_FragCoord");
276941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    } else if (const char* extension =
277941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
278941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionGlobal) {
279941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
280941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText("#extension ");
281941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(extension);
282941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(" : require\n");
283941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            }
284941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
285941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionGlobal = true;
2865961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
287941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("gl_FragCoord");
2885961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else {
289941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionGlobal) {
290941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
291941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
292941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // depending on the surrounding code, accessing .xy with a uniform involved can
293941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
294941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // (and only accessing .xy) seems to "fix" things.
295941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
296941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                                                       : "";
297941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("uniform ");
298941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText(precision);
299941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
300941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionGlobal = true;
301941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
302941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionLocal) {
303941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
304941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                                                       : "";
305941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += precision;
306941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
307941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += precision;
308941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
309941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               " - _sktmpCoord.y, 1.0, 1.0);\n";
310941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionLocal = true;
311941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
312941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("sk_FragCoord");
313941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    }
314941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas}
315941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas
316941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas
317941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasvoid GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
318941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
319941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        case SK_FRAGCOLOR_BUILTIN:
320941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
321941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                this->write("sk_FragColor");
322941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            } else {
323941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                this->write("gl_FragColor");
324941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            }
325941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            break;
326941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        case SK_FRAGCOORD_BUILTIN:
327941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            this->writeFragCoord();
328941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            break;
329a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas        case SK_VERTEXID_BUILTIN:
330a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas            this->write("gl_VertexID");
331a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas            break;
33267d64605d3421404a94c0717fdff194730579873Ethan Nicholas        case SK_CLIPDISTANCE_BUILTIN:
33367d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write("gl_ClipDistance");
33467d64605d3421404a94c0717fdff194730579873Ethan Nicholas            break;
33552cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case SK_IN_BUILTIN:
33652cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            this->write("gl_in");
33752cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
33852cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case SK_INVOCATIONID_BUILTIN:
33952cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            this->write("gl_InvocationID");
34052cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
341941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        default:
342941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            this->write(ref.fVariable.fName);
3435961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
344f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
345f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
346f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
347f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*expr.fBase, kPostfix_Precedence);
348f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("[");
349f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
350f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("]");
351f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
352f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
353f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
354f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
355f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fBase, kPostfix_Precedence);
356f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(".");
357f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
35867d64605d3421404a94c0717fdff194730579873Ethan Nicholas    switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
35967d64605d3421404a94c0717fdff194730579873Ethan Nicholas        case SK_CLIPDISTANCE_BUILTIN:
36067d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write("gl_ClipDistance");
36167d64605d3421404a94c0717fdff194730579873Ethan Nicholas            break;
36267d64605d3421404a94c0717fdff194730579873Ethan Nicholas        default:
36367d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
36467d64605d3421404a94c0717fdff194730579873Ethan Nicholas    }
365f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
366f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
367f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
368f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
369f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(".");
370f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (int c : swizzle.fComponents) {
371f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(&("x\0y\0z\0w\0"[c * 2]));
372f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
373f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
374f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
375f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasstatic GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
376f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (op) {
377f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::STAR:         // fall through
378f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SLASH:        // fall through
379f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
380f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PLUS:         // fall through
381f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
382f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHL:          // fall through
383f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
384f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LT:           // fall through
385f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::GT:           // fall through
386f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LTEQ:         // fall through
387f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
388f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::EQEQ:         // fall through
389f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
390f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
391f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
392f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
393f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
394f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
395f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
396f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::EQ:           // fall through
397f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PLUSEQ:       // fall through
398f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::MINUSEQ:      // fall through
399f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::STAREQ:       // fall through
400f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SLASHEQ:      // fall through
401f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PERCENTEQ:    // fall through
402f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHLEQ:        // fall through
403f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHREQ:        // fall through
404f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALANDEQ: // fall through
405f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALXOREQ: // fall through
406f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALOREQ:  // fall through
407f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEANDEQ: // fall through
408f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEXOREQ: // fall through
409f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
410f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default: ABORT("unsupported binary operator");
411f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
412f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
413f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
414f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
415f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                              Precedence parentPrecedence) {
416f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    Precedence precedence = get_binary_precedence(b.fOperator);
417f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (precedence >= parentPrecedence) {
418f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
419f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
420f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*b.fLeft, precedence);
421f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" " + Token::OperatorName(b.fOperator) + " ");
422f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*b.fRight, precedence);
423f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (precedence >= parentPrecedence) {
424f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
425f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
426f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
427f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
428f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
429f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                               Precedence parentPrecedence) {
430f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kTernary_Precedence >= parentPrecedence) {
431f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
432f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
433f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fTest, kTernary_Precedence);
434f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" ? ");
435f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
436f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" : ");
437f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
438f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kTernary_Precedence >= parentPrecedence) {
439f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
440f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
441f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
442f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
443f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
444f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                              Precedence parentPrecedence) {
445f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPrefix_Precedence >= parentPrecedence) {
446f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
447f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
448f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(Token::OperatorName(p.fOperator));
449f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*p.fOperand, kPrefix_Precedence);
450f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPrefix_Precedence >= parentPrecedence) {
451f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
452f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
453f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
454f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
455f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
456f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                               Precedence parentPrecedence) {
457f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPostfix_Precedence >= parentPrecedence) {
458f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
459f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
460f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*p.fOperand, kPostfix_Precedence);
461f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(Token::OperatorName(p.fOperator));
462f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPostfix_Precedence >= parentPrecedence) {
463f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
464f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
465f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
466f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
467f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
468f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(b.fValue ? "true" : "false");
469f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
470f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
471f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
4725961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (i.fType == *fContext.fUInt_Type) {
4735961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write(to_string(i.fValue & 0xffffffff) + "u");
4745961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else {
4755961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write(to_string((int32_t) i.fValue));
4765961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
477f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
478f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
479f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
480f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(to_string(f.fValue));
481f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
482f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
483f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
484f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeType(f.fDeclaration.fReturnType);
485f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" " + f.fDeclaration.fName + "(");
486f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
487f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& param : f.fDeclaration.fParameters) {
488f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
489f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
4905961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeModifiers(param->fModifiers, false);
4915961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        std::vector<int> sizes;
4925961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        const Type* type = &param->fType;
4935961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        while (type->kind() == Type::kArray_Kind) {
4945961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            sizes.push_back(type->columns());
4955961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            type = &type->componentType();
4965961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
4975961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeType(*type);
498f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" " + param->fName);
4995961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        for (int s : sizes) {
5005961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            if (s <= 0) {
5015961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("[]");
5025961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            } else {
5035961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("[" + to_string(s) + "]");
5045961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            }
5055961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
506f008b0a59f45c0d4bea3e66faf3b01805009ec89ethannicholas    }
5075961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeLine(") {");
5085961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
5095961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fFunctionHeader = "";
5109e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkWStream* oldOut = fOut;
5119e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkDynamicMemoryWStream buffer;
5125961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fOut = &buffer;
5135961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fIndentation++;
514e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    for (const auto& s : f.fBody->fStatements) {
515e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        this->writeStatement(*s);
516e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        this->writeLine();
517e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    }
5185961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fIndentation--;
5195961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeLine("}");
5205961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
5215961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fOut = oldOut;
5225961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(fFunctionHeader);
5239e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    sk_sp<SkData> data(buffer.detachAsData());
5249e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    this->write(SkString((const char*) data->data(), data->size()));
525f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
526f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
52764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
5285961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                       bool globalContext) {
529f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kFlat_Flag) {
530f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("flat ");
531f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
5325961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
5335961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("noperspective ");
5345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5358da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas    SkString layout = modifiers.fLayout.description();
5368da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas    if (layout.size()) {
5378da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas        this->write(layout + " ");
5388da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas    }
539f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
540f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("readonly ");
541f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
542f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
543f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("writeonly ");
544f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
545f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
546f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("coherent ");
547f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
548f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
549f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("volatile ");
550f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
551f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
552f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("restrict ");
5535961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
55464773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
5555961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        (modifiers.fFlags & Modifiers::kOut_Flag)) {
5565961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("inout ");
5575961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
558941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (globalContext &&
559941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
5605961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
5615961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                                              : "varying ");
5625961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        } else {
5635961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("in ");
5645961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5655961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
566941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (globalContext &&
567941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
5685961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("varying ");
5695961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        } else {
5705961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("out ");
5715961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5725961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5735961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kUniform_Flag) {
5745961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("uniform ");
5755961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5765961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kConst_Flag) {
5775961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("const ");
5785961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
579941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
5805961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kLowp_Flag) {
5815961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("lowp ");
5825961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5835961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kMediump_Flag) {
5845961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("mediump ");
5855961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5865961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kHighp_Flag) {
5875961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("highp ");
5885961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5895961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
590f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
591f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
592f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
59352cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas    if (intf.fTypeName == "sk_PerVertex") {
594f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        return;
595f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
5965961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeModifiers(intf.fVariable.fModifiers, true);
59750afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->writeLine(intf.fTypeName + " {");
598f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation++;
59950afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    const Type* structType = &intf.fVariable.fType;
60050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    while (structType->kind() == Type::kArray_Kind) {
60150afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        structType = &structType->componentType();
60250afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    }
60350afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    for (const auto& f : structType->fields()) {
6045961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeModifiers(f.fModifiers, false);
6050730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas        this->writeType(*f.fType);
606f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeLine(" " + f.fName + ";");
607f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
608f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation--;
60950afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->write("}");
61050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    if (intf.fInstanceName.size()) {
61150afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        this->write(" ");
61250afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        this->write(intf.fInstanceName);
61350afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        for (const auto& size : intf.fSizes) {
61450afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            this->write("[");
61550afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            if (size) {
61650afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas                this->writeExpression(*size, kTopLevel_Precedence);
61750afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            }
61850afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            this->write("]");
61950afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        }
62050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    }
62150afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->writeLine(";");
622f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
623f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
6245961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasvoid GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
625f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    ASSERT(decl.fVars.size() > 0);
626e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
627f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeType(decl.fBaseType);
6289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkString separator(" ");
62914fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas    for (const auto& var : decl.fVars) {
630e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
631f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
6329e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        separator = SkString(", ");
633e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        this->write(var.fVar->fName);
634e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        for (const auto& size : var.fSizes) {
635f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("[");
6365961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            if (size) {
6375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->writeExpression(*size, kTopLevel_Precedence);
6385961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            }
639f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("]");
640f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
641e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        if (var.fValue) {
642f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write(" = ");
643e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas            this->writeExpression(*var.fValue, kTopLevel_Precedence);
644f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
645e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
646941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
6479e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                fHeader.writeText("#extension ");
648941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
6499e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                fHeader.writeText(" : require\n");
6502a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon            }
6512a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon            fFoundImageDecl = true;
6522a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon        }
653f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
654f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(";");
655f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
656f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
657f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeStatement(const Statement& s) {
658f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (s.fKind) {
659f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kBlock_Kind:
660f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBlock((Block&) s);
661f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
662f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kExpression_Kind:
663f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
664f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write(";");
665f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
666f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kReturn_Kind:
667f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeReturnStatement((ReturnStatement&) s);
668f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
66914fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        case Statement::kVarDeclarations_Kind:
6705961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
671f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
672f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kIf_Kind:
673f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIfStatement((IfStatement&) s);
674f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
675f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kFor_Kind:
676f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeForStatement((ForStatement&) s);
677f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
678f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kWhile_Kind:
679f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeWhileStatement((WhileStatement&) s);
680f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
681f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kDo_Kind:
682f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeDoStatement((DoStatement&) s);
683f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
684af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        case Statement::kSwitch_Kind:
685af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeSwitchStatement((SwitchStatement&) s);
686af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            break;
687f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kBreak_Kind:
688f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("break;");
689f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
690f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kContinue_Kind:
691f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("continue;");
692f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
693f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kDiscard_Kind:
694f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("discard;");
695f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
696f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default:
697f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            ABORT("unsupported statement: %s", s.description().c_str());
698f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
699f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
700f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
701f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeBlock(const Block& b) {
702f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("{");
703f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation++;
704e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    for (const auto& s : b.fStatements) {
705e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        this->writeStatement(*s);
706e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas        this->writeLine();
707e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas    }
708f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation--;
709f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("}");
710f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
711f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
712f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
713f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("if (");
714f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
715f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
716f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*stmt.fIfTrue);
717f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (stmt.fIfFalse) {
718f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" else ");
719f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeStatement(*stmt.fIfFalse);
720f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
721f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
722f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
723f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
724f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("for (");
725f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fInitializer) {
726f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeStatement(*f.fInitializer);
727f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    } else {
728f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("; ");
729f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
730f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fTest) {
731f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fTest, kTopLevel_Precedence);
732f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
733f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("; ");
734f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fNext) {
735f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fNext, kTopLevel_Precedence);
736f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
737f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
738f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*f.fStatement);
739f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
740f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
741f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
742f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("while (");
743f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*w.fTest, kTopLevel_Precedence);
744f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
745f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*w.fStatement);
746f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
747f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
748f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
749f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("do ");
750f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*d.fStatement);
751f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" while (");
752f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*d.fTest, kTopLevel_Precedence);
753f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(");");
754f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
755f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
756af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholasvoid GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
757af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->write("switch (");
758af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->writeExpression(*s.fValue, kTopLevel_Precedence);
759af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->writeLine(") {");
760af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    fIndentation++;
761af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    for (const auto& c : s.fCases) {
762af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        if (c->fValue) {
763af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->write("case ");
764af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeExpression(*c->fValue, kTopLevel_Precedence);
765af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine(":");
766af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        } else {
767af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine("default:");
768af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        }
769af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        fIndentation++;
770af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        for (const auto& stmt : c->fStatements) {
771af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeStatement(*stmt);
772af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine();
773af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        }
774af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        fIndentation--;
775af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    }
776af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    fIndentation--;
777af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->write("}");
778af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas}
779af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas
780f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
781f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("return");
782f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (r.fExpression) {
783f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" ");
784f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
785f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
786f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(";");
787f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
788f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
789941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasbool GLSLCodeGenerator::generateCode() {
790941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    SkWStream* rawOut = fOut;
791ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    fOut = &fHeader;
792941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    fProgramKind = fProgram.fKind;
793941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->write(fProgram.fSettings.fCaps->versionDeclString());
794f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine();
795941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    for (const auto& e : fProgram.fElements) {
7965961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (e->fKind == ProgramElement::kExtension_Kind) {
7975961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeExtension((Extension&) *e);
7985961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
7995961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
8009e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    SkDynamicMemoryWStream body;
801ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    fOut = &body;
802941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
8035961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("precision ");
804941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        switch (fProgram.fDefaultPrecision) {
8055961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kLowp_Flag:
8065961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("lowp");
8075961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8085961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kMediump_Flag:
8095961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("mediump");
8105961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8115961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kHighp_Flag:
8125961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("highp");
8135961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8145961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            default:
8155961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                ASSERT(false);
8165961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("<error>");
8175961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
8185961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeLine(" float;");
8195961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
820941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    for (const auto& e : fProgram.fElements) {
821f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        switch (e->fKind) {
822f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            case ProgramElement::kExtension_Kind:
823f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                break;
824f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            case ProgramElement::kVar_Kind: {
82514fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas                VarDeclarations& decl = (VarDeclarations&) *e;
8265961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                if (decl.fVars.size() > 0) {
827e1d9cb82bf9004eb05831f34bb3e9e708ae0617fEthan Nicholas                    int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
8285961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                    if (builtin == -1) {
8295961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        // normal var
8305961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        this->writeVarDeclarations(decl, true);
8315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        this->writeLine();
8325961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                    } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
833941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
8345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        this->write("out ");
835941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                        if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
8365961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                            this->write("mediump ");
8375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        }
8385961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                        this->writeLine("vec4 sk_FragColor;");
8395961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                    }
840f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                }
841f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                break;
842f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            }
843f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            case ProgramElement::kInterfaceBlock_Kind:
844f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                this->writeInterfaceBlock((InterfaceBlock&) *e);
845f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                break;
846f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            case ProgramElement::kFunction_Kind:
847f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                this->writeFunction((FunctionDefinition&) *e);
848f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                break;
8495961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case ProgramElement::kModifiers_Kind:
8505961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
8515961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->writeLine(";");
8525961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
853f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            default:
854f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                printf("%s\n", e->description().c_str());
855f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                ABORT("unsupported program element");
856f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
857f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
858f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fOut = nullptr;
859ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas
860941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    write_data(*fHeader.detachAsData(), *rawOut);
861941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    write_data(*body.detachAsData(), *rawOut);
862941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return true;
863f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
864f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
865f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
866