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 "GLSL.std.450.h"
11f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
12941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas#include "SkSLCompiler.h"
13f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLExpressionStatement.h"
14f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLExtension.h"
15f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLIndexExpression.h"
165961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#include "ir/SkSLModifiersDeclaration.h"
17cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas#include "ir/SkSLNop.h"
18f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas#include "ir/SkSLVariableReference.h"
19f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
20f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasnamespace SkSL {
21f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
22f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::write(const char* s) {
23f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (s[0] == 0) {
24f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        return;
25f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
26f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (fAtLineStart) {
27f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (int i = 0; i < fIndentation; i++) {
289e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas            fOut->writeText("    ");
29f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
30f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
319e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas    fOut->writeText(s);
32f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fAtLineStart = false;
33f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
34f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
35f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeLine(const char* s) {
36f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(s);
37762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fOut->writeText(fLineEnding);
38f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fAtLineStart = true;
39f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
40f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
410df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::write(const String& s) {
42f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(s.c_str());
43f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
44f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
450df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::writeLine(const String& s) {
46f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine(s.c_str());
47f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
48f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
49f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeLine() {
50f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("");
51f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
52f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
53f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeExtension(const Extension& ext) {
54f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("#extension " + ext.fName + " : enable");
55f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
56f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
57f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeType(const Type& type) {
58f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (type.kind() == Type::kStruct_Kind) {
59f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (const Type* search : fWrittenStructs) {
60f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            if (*search == type) {
61f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                // already written
62f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                this->write(type.name());
63f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                return;
64f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            }
65f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
66f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fWrittenStructs.push_back(&type);
67f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeLine("struct " + type.name() + " {");
68f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fIndentation++;
69f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        for (const auto& f : type.fields()) {
705961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeModifiers(f.fModifiers, false);
71f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            // sizes (which must be static in structs) are part of the type name here
720730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas            this->writeType(*f.fType);
73f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeLine(" " + f.fName + ";");
74f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
75f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        fIndentation--;
7619671772c1a03bd973fae54dead4defc9ee1d4c3Ethan Nicholas        this->write("}");
77f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    } else {
78f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(type.name());
79f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
80f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
81f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
82f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
83f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (expr.fKind) {
84f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kBinary_Kind:
85f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
86f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
87f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kBoolLiteral_Kind:
88f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBoolLiteral((BoolLiteral&) expr);
89f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
90f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kConstructor_Kind:
91f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeConstructor((Constructor&) expr);
92f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
93f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kIntLiteral_Kind:
94f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIntLiteral((IntLiteral&) expr);
95f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
96f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFieldAccess_Kind:
97f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFieldAccess(((FieldAccess&) expr));
98f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
99f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFloatLiteral_Kind:
100f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFloatLiteral(((FloatLiteral&) expr));
101f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
102f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kFunctionCall_Kind:
103f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeFunctionCall((FunctionCall&) expr);
104f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
105f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kPrefix_Kind:
106f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
107f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
108f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kPostfix_Kind:
109f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
110f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
111762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case Expression::kSetting_Kind:
112762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeSetting((Setting&) expr);
113762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
114f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kSwizzle_Kind:
115f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeSwizzle((Swizzle&) expr);
116f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
117f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kVariableReference_Kind:
118f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeVariableReference((VariableReference&) expr);
119f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
120f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kTernary_Kind:
121f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
122f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
123f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Expression::kIndex_Kind:
124f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIndexExpression((IndexExpression&) expr);
125f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
126f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default:
127f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            ABORT("unsupported expression: %s", expr.description().c_str());
128f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
129f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
130f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
1315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasstatic bool is_abs(Expression& expr) {
1325961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (expr.fKind != Expression::kFunctionCall_Kind) {
1335961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        return false;
1345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
1355961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    return ((FunctionCall&) expr).fFunction.fName == "abs";
1365961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas}
1375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
138941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
1395961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas// Tegra3 compiler bug.
1405961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasvoid GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
141941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
1420df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
1430df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
1445961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->fFunctionHeader += "    " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
1455961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->fFunctionHeader += "    " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
1465961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write("((" + tmpVar1 + " = ");
1475961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeExpression(absExpr, kTopLevel_Precedence);
1485961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(") < (" + tmpVar2 + " = ");
1495961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeExpression(otherExpr, kAssignment_Precedence);
1505961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
1515961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas}
1525961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
153f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
154941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
155941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin) {
1565961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        ASSERT(c.fArguments.size() == 2);
1575961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (is_abs(*c.fArguments[0])) {
1585961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
1595961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            return;
1605961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
1615961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (is_abs(*c.fArguments[1])) {
1625961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
1635961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            // ever end up mattering, but it's worth calling out.
1645961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
1655961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            return;
1665961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
1675961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
168941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
169941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fName == "atan" &&
170941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
171ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas        c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
172ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
173ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        if (p.fOperator == Token::MINUS) {
174ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write("atan(");
175ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->writeExpression(*c.fArguments[0], kSequence_Precedence);
176ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write(", -1.0 * ");
177ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
178ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            this->write(")");
179ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas            return;
180ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas        }
181ad146f6ef5d2de94bd2d8c678757a6274844d20eethannicholas    }
182941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
183941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
184941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
1859e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        fHeader.writeText("#extension ");
186941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
1879e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas        fHeader.writeText(" : require\n");
188ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas        fFoundDerivatives = true;
189ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    }
1902b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
1912b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        const char* dim = "";
1922b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        bool proj = false;
1932b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        switch (c.fArguments[0]->fType.dimensions()) {
1942b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim1D:
1952b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "1D";
1962b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
1972b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
1982b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
1992b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
2002b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
2012b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2022b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2032b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim2D:
2042b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "2D";
2052b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
2062b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
2072b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
2082b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
2092b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
2102b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2112b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2122b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDim3D:
2132b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "3D";
2142b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
2152b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = false;
2162b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                } else {
2172b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    ASSERT(c.fArguments[1]->fType == *fContext.fVec4_Type);
2182b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                    proj = true;
2192b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                }
2202b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2212b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimCube:
2222b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Cube";
2232b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2242b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2252b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimRect:
2262b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Rect";
2272b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2282b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2292b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimBuffer:
2302b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                ASSERT(false); // doesn't exist
2312b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "Buffer";
2322b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2332b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2342b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            case SpvDimSubpassData:
2352b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                ASSERT(false); // doesn't exist
2362b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                dim = "SubpassData";
2372b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                proj = false;
2382b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas                break;
2392b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2402b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        this->write("texture");
241941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
2422b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            this->write(dim);
2432b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2442b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        if (proj) {
2452b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas            this->write("Proj");
2462b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        }
2472b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas
2482b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    } else {
2492b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas        this->write(c.fFunction.fName);
2502b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    }
2512b3dab62bccdbf6244aef9103e9e739147af8616Ethan Nicholas    this->write("(");
252f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
253f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& arg : c.fArguments) {
254f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
255f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
256f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*arg, kSequence_Precedence);
257f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
258f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(")");
259f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
260f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
261f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeConstructor(const Constructor& c) {
262f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(c.fType.name() + "(");
263f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
264f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& arg : c.fArguments) {
265f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
266f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
267f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*arg, kSequence_Precedence);
268f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
269f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(")");
270f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
271f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
272941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasvoid GLSLCodeGenerator::writeFragCoord() {
273941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
274941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
275941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
276941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (!fProgram.fSettings.fFlipY) {
277941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("gl_FragCoord");
278941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    } else if (const char* extension =
279941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
280941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionGlobal) {
281941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
282941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText("#extension ");
283941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(extension);
284941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(" : require\n");
285941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            }
286941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
287941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionGlobal = true;
2885961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
289941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("gl_FragCoord");
2905961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else {
291941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionGlobal) {
292941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
293941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
294941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // depending on the surrounding code, accessing .xy with a uniform involved can
295941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
296941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            // (and only accessing .xy) seems to "fix" things.
297941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
298941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                                                       : "";
299941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("uniform ");
300941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText(precision);
301941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
302941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionGlobal = true;
303941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
304941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (!fSetupFragPositionLocal) {
305941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
306941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                                                       : "";
307941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += precision;
308941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
309941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += precision;
310941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
311941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                               " - _sktmpCoord.y, 1.0, 1.0);\n";
312941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fSetupFragPositionLocal = true;
313941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
314941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        this->write("sk_FragCoord");
315941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    }
316941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas}
317941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas
318941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas
319941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasvoid GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
320941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
321941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        case SK_FRAGCOLOR_BUILTIN:
322941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
323941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                this->write("sk_FragColor");
324941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            } else {
325941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                this->write("gl_FragColor");
326941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            }
327941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            break;
328941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        case SK_FRAGCOORD_BUILTIN:
329941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            this->writeFragCoord();
330941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            break;
331a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas        case SK_VERTEXID_BUILTIN:
332a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas            this->write("gl_VertexID");
333a51740c4f879b3c15877975118ef7588b99eaaeaEthan Nicholas            break;
33467d64605d3421404a94c0717fdff194730579873Ethan Nicholas        case SK_CLIPDISTANCE_BUILTIN:
33567d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write("gl_ClipDistance");
33667d64605d3421404a94c0717fdff194730579873Ethan Nicholas            break;
33752cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case SK_IN_BUILTIN:
33852cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            this->write("gl_in");
33952cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
34052cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case SK_INVOCATIONID_BUILTIN:
34152cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            this->write("gl_InvocationID");
34252cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
343941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        default:
344941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            this->write(ref.fVariable.fName);
3455961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
346f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
347f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
348f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
349f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*expr.fBase, kPostfix_Precedence);
350f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("[");
351f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
352f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("]");
353f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
354f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
355f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
356f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
357f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fBase, kPostfix_Precedence);
358f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(".");
359f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
36067d64605d3421404a94c0717fdff194730579873Ethan Nicholas    switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
36167d64605d3421404a94c0717fdff194730579873Ethan Nicholas        case SK_CLIPDISTANCE_BUILTIN:
36267d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write("gl_ClipDistance");
36367d64605d3421404a94c0717fdff194730579873Ethan Nicholas            break;
36467d64605d3421404a94c0717fdff194730579873Ethan Nicholas        default:
36567d64605d3421404a94c0717fdff194730579873Ethan Nicholas            this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
36667d64605d3421404a94c0717fdff194730579873Ethan Nicholas    }
367f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
368f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
369f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
370f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
371f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(".");
372f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (int c : swizzle.fComponents) {
373f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(&("x\0y\0z\0w\0"[c * 2]));
374f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
375f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
376f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
377762466e9fe0478bcf11fba532998e81e33b3069eEthan NicholasGLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
378f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (op) {
379f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::STAR:         // fall through
380f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SLASH:        // fall through
381f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
382f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PLUS:         // fall through
383f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
384f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHL:          // fall through
385f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
386f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LT:           // fall through
387f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::GT:           // fall through
388f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LTEQ:         // fall through
389f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
390f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::EQEQ:         // fall through
391f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
392f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
393f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
394f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
395f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
396f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
397f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
398f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::EQ:           // fall through
399f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PLUSEQ:       // fall through
400f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::MINUSEQ:      // fall through
401f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::STAREQ:       // fall through
402f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SLASHEQ:      // fall through
403f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::PERCENTEQ:    // fall through
404f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHLEQ:        // fall through
405f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::SHREQ:        // fall through
406f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALANDEQ: // fall through
407f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALXOREQ: // fall through
408f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::LOGICALOREQ:  // fall through
409f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEANDEQ: // fall through
410f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEXOREQ: // fall through
411f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
4124b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        case Token::COMMA:        return GLSLCodeGenerator::kSequence_Precedence;
413f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default: ABORT("unsupported binary operator");
414f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
415f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
416f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
4170df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
418f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                              Precedence parentPrecedence) {
419762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    Precedence precedence = GetBinaryPrecedence(b.fOperator);
420f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (precedence >= parentPrecedence) {
421f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
422f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
423f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*b.fLeft, precedence);
424f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" " + Token::OperatorName(b.fOperator) + " ");
425f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*b.fRight, precedence);
426f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (precedence >= parentPrecedence) {
427f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
428f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
429f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
430f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
4310df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
432f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                               Precedence parentPrecedence) {
433f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kTernary_Precedence >= parentPrecedence) {
434f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
435f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
436f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fTest, kTernary_Precedence);
437f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" ? ");
438f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
439f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" : ");
440f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
441f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kTernary_Precedence >= parentPrecedence) {
442f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
443f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
444f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
445f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
4460df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
447f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                              Precedence parentPrecedence) {
448f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPrefix_Precedence >= parentPrecedence) {
449f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
450f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
451f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(Token::OperatorName(p.fOperator));
452f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*p.fOperand, kPrefix_Precedence);
453f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPrefix_Precedence >= parentPrecedence) {
454f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
455f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
456f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
457f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
4580df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
459f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                                               Precedence parentPrecedence) {
460f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPostfix_Precedence >= parentPrecedence) {
461f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("(");
462f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
463f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*p.fOperand, kPostfix_Precedence);
464f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(Token::OperatorName(p.fOperator));
465f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (kPostfix_Precedence >= parentPrecedence) {
466f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(")");
467f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
468f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
469f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
470f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
471f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(b.fValue ? "true" : "false");
472f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
473f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
474f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
4755961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (i.fType == *fContext.fUInt_Type) {
4765961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write(to_string(i.fValue & 0xffffffff) + "u");
4775961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else {
4785961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write(to_string((int32_t) i.fValue));
4795961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
480f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
481f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
482f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
483f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(to_string(f.fValue));
484f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
485f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
486762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasvoid GLSLCodeGenerator::writeSetting(const Setting& s) {
487762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    ABORT("internal error; setting was not folded to a constant during compilation\n");
488762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
489762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
490f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
491f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeType(f.fDeclaration.fReturnType);
492f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" " + f.fDeclaration.fName + "(");
493f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    const char* separator = "";
494f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    for (const auto& param : f.fDeclaration.fParameters) {
495f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(separator);
496f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        separator = ", ";
4975961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeModifiers(param->fModifiers, false);
4985961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        std::vector<int> sizes;
4995961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        const Type* type = &param->fType;
5005961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        while (type->kind() == Type::kArray_Kind) {
5015961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            sizes.push_back(type->columns());
5025961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            type = &type->componentType();
5035961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5045961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeType(*type);
505f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" " + param->fName);
5065961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        for (int s : sizes) {
5075961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            if (s <= 0) {
5085961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("[]");
5095961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            } else {
5105961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("[" + to_string(s) + "]");
5115961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            }
5125961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
513f008b0a59f45c0d4bea3e66faf3b01805009ec89ethannicholas    }
5145961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeLine(") {");
5155961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
5165961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fFunctionHeader = "";
5170df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    OutputStream* oldOut = fOut;
5180df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    StringStream buffer;
5195961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fOut = &buffer;
5205961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fIndentation++;
521cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    this->writeStatements(((Block&) *f.fBody).fStatements);
5225961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fIndentation--;
5235961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeLine("}");
5245961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
5255961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    fOut = oldOut;
5265961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->write(fFunctionHeader);
527762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->write(buffer.str());
528f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
529f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
53064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Danielvoid GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
5315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                       bool globalContext) {
532f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kFlat_Flag) {
533f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("flat ");
534f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
5355961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
5365961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("noperspective ");
5375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5380df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    String layout = modifiers.fLayout.description();
5398da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas    if (layout.size()) {
5408da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas        this->write(layout + " ");
5418da9e940721168143d6296f578b6d7423de55d69Ethan Nicholas    }
542f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
543f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("readonly ");
544f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
545f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
546f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("writeonly ");
547f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
548f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
549f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("coherent ");
550f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
551f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
552f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("volatile ");
553f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    }
554f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon    if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
555f9f451213a3951d8a61568998de2ddbd643f6693Brian Salomon        this->write("restrict ");
5565961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
55764773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
5585961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        (modifiers.fFlags & Modifiers::kOut_Flag)) {
5595961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("inout ");
5605961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
561941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (globalContext &&
562941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
5635961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
5645961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                                                              : "varying ");
5655961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        } else {
5665961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("in ");
5675961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5685961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
569941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (globalContext &&
570941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
5715961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("varying ");
5725961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        } else {
5735961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("out ");
5745961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5755961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5765961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kUniform_Flag) {
5775961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("uniform ");
5785961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
5795961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    if (modifiers.fFlags & Modifiers::kConst_Flag) {
5805961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("const ");
5815961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
582941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
5835961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kLowp_Flag) {
5845961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("lowp ");
5855961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5865961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kMediump_Flag) {
5875961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("mediump ");
5885961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5895961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (modifiers.fFlags & Modifiers::kHighp_Flag) {
5905961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->write("highp ");
5915961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
5925961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
593f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
594f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
595f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
59652cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas    if (intf.fTypeName == "sk_PerVertex") {
597f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        return;
598f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
5995961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    this->writeModifiers(intf.fVariable.fModifiers, true);
60050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->writeLine(intf.fTypeName + " {");
601f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation++;
60250afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    const Type* structType = &intf.fVariable.fType;
60350afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    while (structType->kind() == Type::kArray_Kind) {
60450afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        structType = &structType->componentType();
60550afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    }
60650afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    for (const auto& f : structType->fields()) {
6075961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeModifiers(f.fModifiers, false);
6080730be7c303ac415484b15ef44ff1dce077a93b8ethannicholas        this->writeType(*f.fType);
609f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeLine(" " + f.fName + ";");
610f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
611f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation--;
61250afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->write("}");
61350afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    if (intf.fInstanceName.size()) {
61450afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        this->write(" ");
61550afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        this->write(intf.fInstanceName);
61650afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        for (const auto& size : intf.fSizes) {
61750afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            this->write("[");
61850afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            if (size) {
61950afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas                this->writeExpression(*size, kTopLevel_Precedence);
62050afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            }
62150afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas            this->write("]");
62250afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas        }
62350afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    }
62450afc1765511a8d4850fe97aacf8714b609bfd5aEthan Nicholas    this->writeLine(";");
625f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
626f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
627762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasvoid GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
628762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->writeExpression(value, kTopLevel_Precedence);
629762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
630762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
6315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasvoid GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
632f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    ASSERT(decl.fVars.size() > 0);
633b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas    bool wroteType = false;
634b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas    for (const auto& stmt : decl.fVars) {
635b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        VarDeclaration& var = (VarDeclaration&) *stmt;
636b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        if (wroteType) {
637b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            this->write(", ");
638b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        } else {
639b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            this->writeModifiers(var.fVar->fModifiers, global);
640b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            this->writeType(decl.fBaseType);
641b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            this->write(" ");
642b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            wroteType = true;
643b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        }
644b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        this->write(var.fVar->fName);
645b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        for (const auto& size : var.fSizes) {
646f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("[");
6475961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            if (size) {
6485961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->writeExpression(*size, kTopLevel_Precedence);
6495961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            }
650f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("]");
651f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
652b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        if (var.fValue) {
653f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write(" = ");
654762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeVarInitializer(*var.fVar, *var.fValue);
655f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
656b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
657941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
6589e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                fHeader.writeText("#extension ");
659941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
6609e1138d56665d13641f8805cd72ae81adc255f79Ethan Nicholas                fHeader.writeText(" : require\n");
6612a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon            }
6622a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon            fFoundImageDecl = true;
6632a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon        }
664f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
665b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas    if (wroteType) {
666b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        this->write(";");
667b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas    }
668f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
669f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
670f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeStatement(const Statement& s) {
671f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    switch (s.fKind) {
672f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kBlock_Kind:
673f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeBlock((Block&) s);
674f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
675f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kExpression_Kind:
676f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
677f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write(";");
678f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
6790df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas        case Statement::kReturn_Kind:
680f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeReturnStatement((ReturnStatement&) s);
681f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
68214fe8cc16d2a98d5a96f818e4d0b7127ecad59e2ethannicholas        case Statement::kVarDeclarations_Kind:
6835961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
684f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
685f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kIf_Kind:
686f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeIfStatement((IfStatement&) s);
687f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
688f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kFor_Kind:
689f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeForStatement((ForStatement&) s);
690f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
691f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kWhile_Kind:
692f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeWhileStatement((WhileStatement&) s);
693f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
694f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kDo_Kind:
695f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->writeDoStatement((DoStatement&) s);
696f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
697af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        case Statement::kSwitch_Kind:
698af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeSwitchStatement((SwitchStatement&) s);
699af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            break;
700f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kBreak_Kind:
701f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("break;");
702f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
703f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kContinue_Kind:
704f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("continue;");
705f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
706f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        case Statement::kDiscard_Kind:
707f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            this->write("discard;");
708f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            break;
709cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Statement::kNop_Kind:
710cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            this->write(";");
711cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
712f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        default:
713f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            ABORT("unsupported statement: %s", s.description().c_str());
714f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
715f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
716f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
717cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
718cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    for (const auto& s : statements) {
719cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        if (!s->isEmpty()) {
720cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            this->writeStatement(*s);
721cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            this->writeLine();
722cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
723cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
724cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
725cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
726f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeBlock(const Block& b) {
727f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine("{");
728f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation++;
729cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    this->writeStatements(b.fStatements);
730f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    fIndentation--;
731f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("}");
732f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
733f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
734f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
735f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("if (");
736f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
737f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
738f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*stmt.fIfTrue);
739f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (stmt.fIfFalse) {
740f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" else ");
741f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeStatement(*stmt.fIfFalse);
742f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
743f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
744f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
745f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
746f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("for (");
747b310fd597fc37dee888cfd5a760c4e156af08a6dEthan Nicholas    if (f.fInitializer && !f.fInitializer->isEmpty()) {
748f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeStatement(*f.fInitializer);
749f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    } else {
750f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write("; ");
751f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
752f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fTest) {
753f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fTest, kTopLevel_Precedence);
754f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
755f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("; ");
756f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (f.fNext) {
757f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*f.fNext, kTopLevel_Precedence);
758f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
759f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
760f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*f.fStatement);
761f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
762f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
763f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
764f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("while (");
765f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*w.fTest, kTopLevel_Precedence);
766f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(") ");
767f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*w.fStatement);
768f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
769f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
770f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
771f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("do ");
772f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeStatement(*d.fStatement);
773f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(" while (");
774f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeExpression(*d.fTest, kTopLevel_Precedence);
775f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(");");
776f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
777f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
778af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholasvoid GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
779af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->write("switch (");
780af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->writeExpression(*s.fValue, kTopLevel_Precedence);
781af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->writeLine(") {");
782af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    fIndentation++;
783af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    for (const auto& c : s.fCases) {
784af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        if (c->fValue) {
785af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->write("case ");
786af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeExpression(*c->fValue, kTopLevel_Precedence);
787af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine(":");
788af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        } else {
789af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine("default:");
790af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        }
791af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        fIndentation++;
792af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        for (const auto& stmt : c->fStatements) {
793af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeStatement(*stmt);
794af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas            this->writeLine();
795af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        }
796af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas        fIndentation--;
797af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    }
798af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    fIndentation--;
799af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas    this->write("}");
800af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas}
801af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas
802f789b3893579b773bb4d7be6c2c65311500b53bbethannicholasvoid GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
803f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write("return");
804f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    if (r.fExpression) {
805f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->write(" ");
806f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
807f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
808f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->write(";");
809f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
810f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
811762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasvoid GLSLCodeGenerator::writeHeader() {
812941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->write(fProgram.fSettings.fCaps->versionDeclString());
813f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    this->writeLine();
814941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    for (const auto& e : fProgram.fElements) {
8155961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        if (e->fKind == ProgramElement::kExtension_Kind) {
8165961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            this->writeExtension((Extension&) *e);
8175961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
8185961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
819762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
820762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
821762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasvoid GLSLCodeGenerator::writePrecisionModifier() {
822941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
8235961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->write("precision ");
824941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        switch (fProgram.fDefaultPrecision) {
8255961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kLowp_Flag:
8265961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("lowp");
8275961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8285961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kMediump_Flag:
8295961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("mediump");
8305961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8315961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            case Modifiers::kHighp_Flag:
8325961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("highp");
8335961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                break;
8345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas            default:
8355961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                ASSERT(false);
8365961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                this->write("<error>");
8375961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        }
8385961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas        this->writeLine(" float;");
8395961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
840762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
841762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
842762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasvoid GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
843762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    switch (e.fKind) {
844762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case ProgramElement::kExtension_Kind:
845762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
846762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case ProgramElement::kVar_Kind: {
847762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            VarDeclarations& decl = (VarDeclarations&) e;
848762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            if (decl.fVars.size() > 0) {
849762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
850762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                if (builtin == -1) {
851762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    // normal var
852762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    this->writeVarDeclarations(decl, true);
853762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    this->writeLine();
854762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
855762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                           fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
856762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    this->write("out ");
857762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
858762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                        this->write("mediump ");
8595961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                    }
860762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                    this->writeLine("vec4 sk_FragColor;");
861f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas                }
862f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas            }
863762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
864f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas        }
865762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case ProgramElement::kInterfaceBlock_Kind:
866762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeInterfaceBlock((InterfaceBlock&) e);
867762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
868762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case ProgramElement::kFunction_Kind:
869762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeFunction((FunctionDefinition&) e);
870762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
871762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case ProgramElement::kModifiers_Kind:
872762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeModifiers(((ModifiersDeclaration&) e).fModifiers, true);
873762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            this->writeLine(";");
874762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
875762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        default:
876762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            printf("%s\n", e.description().c_str());
877762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            ABORT("unsupported program element");
878762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    }
879762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
880762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
881762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasbool GLSLCodeGenerator::generateCode() {
882762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    OutputStream* rawOut = fOut;
883762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fOut = &fHeader;
884762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fProgramKind = fProgram.fKind;
885762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->writeHeader();
886762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    StringStream body;
887762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fOut = &body;
888762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->writePrecisionModifier();
889762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    for (const auto& e : fProgram.fElements) {
890762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        this->writeProgramElement(*e);
891f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
892762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fOut = rawOut;
893ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas
8940df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    write_stringstream(fHeader, *rawOut);
8950df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    write_stringstream(body, *rawOut);
896941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return true;
897f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
898f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
899f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
900