1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkSLGLSLCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
14#include "SkSLCompiler.h"
15#include "ir/SkSLExpressionStatement.h"
16#include "ir/SkSLExtension.h"
17#include "ir/SkSLIndexExpression.h"
18#include "ir/SkSLModifiersDeclaration.h"
19#include "ir/SkSLVariableReference.h"
20
21namespace SkSL {
22
23void GLSLCodeGenerator::write(const char* s) {
24    if (s[0] == 0) {
25        return;
26    }
27    if (fAtLineStart) {
28        for (int i = 0; i < fIndentation; i++) {
29            fOut->writeText("    ");
30        }
31    }
32    fOut->writeText(s);
33    fAtLineStart = false;
34}
35
36void GLSLCodeGenerator::writeLine(const char* s) {
37    this->write(s);
38    fOut->writeText("\n");
39    fAtLineStart = true;
40}
41
42void GLSLCodeGenerator::write(const SkString& s) {
43    this->write(s.c_str());
44}
45
46void GLSLCodeGenerator::writeLine(const SkString& s) {
47    this->writeLine(s.c_str());
48}
49
50void GLSLCodeGenerator::writeLine() {
51    this->writeLine("");
52}
53
54void GLSLCodeGenerator::writeExtension(const Extension& ext) {
55    this->writeLine("#extension " + ext.fName + " : enable");
56}
57
58void GLSLCodeGenerator::writeType(const Type& type) {
59    if (type.kind() == Type::kStruct_Kind) {
60        for (const Type* search : fWrittenStructs) {
61            if (*search == type) {
62                // already written
63                this->write(type.name());
64                return;
65            }
66        }
67        fWrittenStructs.push_back(&type);
68        this->writeLine("struct " + type.name() + " {");
69        fIndentation++;
70        for (const auto& f : type.fields()) {
71            this->writeModifiers(f.fModifiers, false);
72            // sizes (which must be static in structs) are part of the type name here
73            this->writeType(*f.fType);
74            this->writeLine(" " + f.fName + ";");
75        }
76        fIndentation--;
77        this->write("}");
78    } else {
79        this->write(type.name());
80    }
81}
82
83void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
84    switch (expr.fKind) {
85        case Expression::kBinary_Kind:
86            this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
87            break;
88        case Expression::kBoolLiteral_Kind:
89            this->writeBoolLiteral((BoolLiteral&) expr);
90            break;
91        case Expression::kConstructor_Kind:
92            this->writeConstructor((Constructor&) expr);
93            break;
94        case Expression::kIntLiteral_Kind:
95            this->writeIntLiteral((IntLiteral&) expr);
96            break;
97        case Expression::kFieldAccess_Kind:
98            this->writeFieldAccess(((FieldAccess&) expr));
99            break;
100        case Expression::kFloatLiteral_Kind:
101            this->writeFloatLiteral(((FloatLiteral&) expr));
102            break;
103        case Expression::kFunctionCall_Kind:
104            this->writeFunctionCall((FunctionCall&) expr);
105            break;
106        case Expression::kPrefix_Kind:
107            this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
108            break;
109        case Expression::kPostfix_Kind:
110            this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
111            break;
112        case Expression::kSwizzle_Kind:
113            this->writeSwizzle((Swizzle&) expr);
114            break;
115        case Expression::kVariableReference_Kind:
116            this->writeVariableReference((VariableReference&) expr);
117            break;
118        case Expression::kTernary_Kind:
119            this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
120            break;
121        case Expression::kIndex_Kind:
122            this->writeIndexExpression((IndexExpression&) expr);
123            break;
124        default:
125            ABORT("unsupported expression: %s", expr.description().c_str());
126    }
127}
128
129static bool is_abs(Expression& expr) {
130    if (expr.fKind != Expression::kFunctionCall_Kind) {
131        return false;
132    }
133    return ((FunctionCall&) expr).fFunction.fName == "abs";
134}
135
136// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
137// Tegra3 compiler bug.
138void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
139    ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
140    SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
141    SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
142    this->fFunctionHeader += "    " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
143    this->fFunctionHeader += "    " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
144    this->write("((" + tmpVar1 + " = ");
145    this->writeExpression(absExpr, kTopLevel_Precedence);
146    this->write(") < (" + tmpVar2 + " = ");
147    this->writeExpression(otherExpr, kAssignment_Precedence);
148    this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
149}
150
151void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
152    if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
153        c.fFunction.fBuiltin) {
154        ASSERT(c.fArguments.size() == 2);
155        if (is_abs(*c.fArguments[0])) {
156            this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
157            return;
158        }
159        if (is_abs(*c.fArguments[1])) {
160            // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
161            // ever end up mattering, but it's worth calling out.
162            this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
163            return;
164        }
165    }
166    if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
167        c.fFunction.fName == "atan" &&
168        c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
169        c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
170        const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
171        if (p.fOperator == Token::MINUS) {
172            this->write("atan(");
173            this->writeExpression(*c.fArguments[0], kSequence_Precedence);
174            this->write(", -1.0 * ");
175            this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
176            this->write(")");
177            return;
178        }
179    }
180    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
181        c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
182        ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
183        fHeader.writeText("#extension ");
184        fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
185        fHeader.writeText(" : require\n");
186        fFoundDerivatives = true;
187    }
188    if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
189        const char* dim = "";
190        bool proj = false;
191        switch (c.fArguments[0]->fType.dimensions()) {
192            case SpvDim1D:
193                dim = "1D";
194                if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
195                    proj = false;
196                } else {
197                    ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
198                    proj = true;
199                }
200                break;
201            case SpvDim2D:
202                dim = "2D";
203                if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
204                    proj = false;
205                } else {
206                    ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
207                    proj = true;
208                }
209                break;
210            case SpvDim3D:
211                dim = "3D";
212                if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
213                    proj = false;
214                } else {
215                    ASSERT(c.fArguments[1]->fType == *fContext.fVec4_Type);
216                    proj = true;
217                }
218                break;
219            case SpvDimCube:
220                dim = "Cube";
221                proj = false;
222                break;
223            case SpvDimRect:
224                dim = "Rect";
225                proj = false;
226                break;
227            case SpvDimBuffer:
228                ASSERT(false); // doesn't exist
229                dim = "Buffer";
230                proj = false;
231                break;
232            case SpvDimSubpassData:
233                ASSERT(false); // doesn't exist
234                dim = "SubpassData";
235                proj = false;
236                break;
237        }
238        this->write("texture");
239        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
240            this->write(dim);
241        }
242        if (proj) {
243            this->write("Proj");
244        }
245
246    } else {
247        this->write(c.fFunction.fName);
248    }
249    this->write("(");
250    const char* separator = "";
251    for (const auto& arg : c.fArguments) {
252        this->write(separator);
253        separator = ", ";
254        this->writeExpression(*arg, kSequence_Precedence);
255    }
256    this->write(")");
257}
258
259void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
260    this->write(c.fType.name() + "(");
261    const char* separator = "";
262    for (const auto& arg : c.fArguments) {
263        this->write(separator);
264        separator = ", ";
265        this->writeExpression(*arg, kSequence_Precedence);
266    }
267    this->write(")");
268}
269
270void GLSLCodeGenerator::writeFragCoord() {
271    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
272    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
273    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
274    if (!fProgram.fSettings.fFlipY) {
275        this->write("gl_FragCoord");
276    } else if (const char* extension =
277               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
278        if (!fSetupFragPositionGlobal) {
279            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
280                fHeader.writeText("#extension ");
281                fHeader.writeText(extension);
282                fHeader.writeText(" : require\n");
283            }
284            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
285            fSetupFragPositionGlobal = true;
286        }
287        this->write("gl_FragCoord");
288    } else {
289        if (!fSetupFragPositionGlobal) {
290            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
291            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
292            // depending on the surrounding code, accessing .xy with a uniform involved can
293            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
294            // (and only accessing .xy) seems to "fix" things.
295            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
296                                                                                       : "";
297            fHeader.writeText("uniform ");
298            fHeader.writeText(precision);
299            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
300            fSetupFragPositionGlobal = true;
301        }
302        if (!fSetupFragPositionLocal) {
303            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
304                                                                                       : "";
305            fFunctionHeader += precision;
306            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
307            fFunctionHeader += precision;
308            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
309                               " - _sktmpCoord.y, 1.0, 1.0);\n";
310            fSetupFragPositionLocal = true;
311        }
312        this->write("sk_FragCoord");
313    }
314}
315
316
317void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
318    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
319        case SK_FRAGCOLOR_BUILTIN:
320            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
321                this->write("sk_FragColor");
322            } else {
323                this->write("gl_FragColor");
324            }
325            break;
326        case SK_FRAGCOORD_BUILTIN:
327            this->writeFragCoord();
328            break;
329        case SK_VERTEXID_BUILTIN:
330            this->write("gl_VertexID");
331            break;
332        case SK_CLIPDISTANCE_BUILTIN:
333            this->write("gl_ClipDistance");
334            break;
335        case SK_IN_BUILTIN:
336            this->write("gl_in");
337            break;
338        case SK_INVOCATIONID_BUILTIN:
339            this->write("gl_InvocationID");
340            break;
341        default:
342            this->write(ref.fVariable.fName);
343    }
344}
345
346void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
347    this->writeExpression(*expr.fBase, kPostfix_Precedence);
348    this->write("[");
349    this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
350    this->write("]");
351}
352
353void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
354    if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
355        this->writeExpression(*f.fBase, kPostfix_Precedence);
356        this->write(".");
357    }
358    switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
359        case SK_CLIPDISTANCE_BUILTIN:
360            this->write("gl_ClipDistance");
361            break;
362        default:
363            this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
364    }
365}
366
367void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
368    this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
369    this->write(".");
370    for (int c : swizzle.fComponents) {
371        this->write(&("x\0y\0z\0w\0"[c * 2]));
372    }
373}
374
375static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
376    switch (op) {
377        case Token::STAR:         // fall through
378        case Token::SLASH:        // fall through
379        case Token::PERCENT:      return GLSLCodeGenerator::kMultiplicative_Precedence;
380        case Token::PLUS:         // fall through
381        case Token::MINUS:        return GLSLCodeGenerator::kAdditive_Precedence;
382        case Token::SHL:          // fall through
383        case Token::SHR:          return GLSLCodeGenerator::kShift_Precedence;
384        case Token::LT:           // fall through
385        case Token::GT:           // fall through
386        case Token::LTEQ:         // fall through
387        case Token::GTEQ:         return GLSLCodeGenerator::kRelational_Precedence;
388        case Token::EQEQ:         // fall through
389        case Token::NEQ:          return GLSLCodeGenerator::kEquality_Precedence;
390        case Token::BITWISEAND:   return GLSLCodeGenerator::kBitwiseAnd_Precedence;
391        case Token::BITWISEXOR:   return GLSLCodeGenerator::kBitwiseXor_Precedence;
392        case Token::BITWISEOR:    return GLSLCodeGenerator::kBitwiseOr_Precedence;
393        case Token::LOGICALAND:   return GLSLCodeGenerator::kLogicalAnd_Precedence;
394        case Token::LOGICALXOR:   return GLSLCodeGenerator::kLogicalXor_Precedence;
395        case Token::LOGICALOR:    return GLSLCodeGenerator::kLogicalOr_Precedence;
396        case Token::EQ:           // fall through
397        case Token::PLUSEQ:       // fall through
398        case Token::MINUSEQ:      // fall through
399        case Token::STAREQ:       // fall through
400        case Token::SLASHEQ:      // fall through
401        case Token::PERCENTEQ:    // fall through
402        case Token::SHLEQ:        // fall through
403        case Token::SHREQ:        // fall through
404        case Token::LOGICALANDEQ: // fall through
405        case Token::LOGICALXOREQ: // fall through
406        case Token::LOGICALOREQ:  // fall through
407        case Token::BITWISEANDEQ: // fall through
408        case Token::BITWISEXOREQ: // fall through
409        case Token::BITWISEOREQ:  return GLSLCodeGenerator::kAssignment_Precedence;
410        default: ABORT("unsupported binary operator");
411    }
412}
413
414void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
415                                              Precedence parentPrecedence) {
416    Precedence precedence = get_binary_precedence(b.fOperator);
417    if (precedence >= parentPrecedence) {
418        this->write("(");
419    }
420    this->writeExpression(*b.fLeft, precedence);
421    this->write(" " + Token::OperatorName(b.fOperator) + " ");
422    this->writeExpression(*b.fRight, precedence);
423    if (precedence >= parentPrecedence) {
424        this->write(")");
425    }
426}
427
428void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
429                                               Precedence parentPrecedence) {
430    if (kTernary_Precedence >= parentPrecedence) {
431        this->write("(");
432    }
433    this->writeExpression(*t.fTest, kTernary_Precedence);
434    this->write(" ? ");
435    this->writeExpression(*t.fIfTrue, kTernary_Precedence);
436    this->write(" : ");
437    this->writeExpression(*t.fIfFalse, kTernary_Precedence);
438    if (kTernary_Precedence >= parentPrecedence) {
439        this->write(")");
440    }
441}
442
443void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
444                                              Precedence parentPrecedence) {
445    if (kPrefix_Precedence >= parentPrecedence) {
446        this->write("(");
447    }
448    this->write(Token::OperatorName(p.fOperator));
449    this->writeExpression(*p.fOperand, kPrefix_Precedence);
450    if (kPrefix_Precedence >= parentPrecedence) {
451        this->write(")");
452    }
453}
454
455void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
456                                               Precedence parentPrecedence) {
457    if (kPostfix_Precedence >= parentPrecedence) {
458        this->write("(");
459    }
460    this->writeExpression(*p.fOperand, kPostfix_Precedence);
461    this->write(Token::OperatorName(p.fOperator));
462    if (kPostfix_Precedence >= parentPrecedence) {
463        this->write(")");
464    }
465}
466
467void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
468    this->write(b.fValue ? "true" : "false");
469}
470
471void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
472    if (i.fType == *fContext.fUInt_Type) {
473        this->write(to_string(i.fValue & 0xffffffff) + "u");
474    } else {
475        this->write(to_string((int32_t) i.fValue));
476    }
477}
478
479void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
480    this->write(to_string(f.fValue));
481}
482
483void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
484    this->writeType(f.fDeclaration.fReturnType);
485    this->write(" " + f.fDeclaration.fName + "(");
486    const char* separator = "";
487    for (const auto& param : f.fDeclaration.fParameters) {
488        this->write(separator);
489        separator = ", ";
490        this->writeModifiers(param->fModifiers, false);
491        std::vector<int> sizes;
492        const Type* type = &param->fType;
493        while (type->kind() == Type::kArray_Kind) {
494            sizes.push_back(type->columns());
495            type = &type->componentType();
496        }
497        this->writeType(*type);
498        this->write(" " + param->fName);
499        for (int s : sizes) {
500            if (s <= 0) {
501                this->write("[]");
502            } else {
503                this->write("[" + to_string(s) + "]");
504            }
505        }
506    }
507    this->writeLine(") {");
508
509    fFunctionHeader = "";
510    SkWStream* oldOut = fOut;
511    SkDynamicMemoryWStream buffer;
512    fOut = &buffer;
513    fIndentation++;
514    for (const auto& s : f.fBody->fStatements) {
515        this->writeStatement(*s);
516        this->writeLine();
517    }
518    fIndentation--;
519    this->writeLine("}");
520
521    fOut = oldOut;
522    this->write(fFunctionHeader);
523    sk_sp<SkData> data(buffer.detachAsData());
524    this->write(SkString((const char*) data->data(), data->size()));
525}
526
527void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
528                                       bool globalContext) {
529    if (modifiers.fFlags & Modifiers::kFlat_Flag) {
530        this->write("flat ");
531    }
532    if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
533        this->write("noperspective ");
534    }
535    SkString layout = modifiers.fLayout.description();
536    if (layout.size()) {
537        this->write(layout + " ");
538    }
539    if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
540        this->write("readonly ");
541    }
542    if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
543        this->write("writeonly ");
544    }
545    if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
546        this->write("coherent ");
547    }
548    if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
549        this->write("volatile ");
550    }
551    if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
552        this->write("restrict ");
553    }
554    if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
555        (modifiers.fFlags & Modifiers::kOut_Flag)) {
556        this->write("inout ");
557    } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
558        if (globalContext &&
559            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
560            this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
561                                                              : "varying ");
562        } else {
563            this->write("in ");
564        }
565    } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
566        if (globalContext &&
567            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
568            this->write("varying ");
569        } else {
570            this->write("out ");
571        }
572    }
573    if (modifiers.fFlags & Modifiers::kUniform_Flag) {
574        this->write("uniform ");
575    }
576    if (modifiers.fFlags & Modifiers::kConst_Flag) {
577        this->write("const ");
578    }
579    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
580        if (modifiers.fFlags & Modifiers::kLowp_Flag) {
581            this->write("lowp ");
582        }
583        if (modifiers.fFlags & Modifiers::kMediump_Flag) {
584            this->write("mediump ");
585        }
586        if (modifiers.fFlags & Modifiers::kHighp_Flag) {
587            this->write("highp ");
588        }
589    }
590}
591
592void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
593    if (intf.fTypeName == "sk_PerVertex") {
594        return;
595    }
596    this->writeModifiers(intf.fVariable.fModifiers, true);
597    this->writeLine(intf.fTypeName + " {");
598    fIndentation++;
599    const Type* structType = &intf.fVariable.fType;
600    while (structType->kind() == Type::kArray_Kind) {
601        structType = &structType->componentType();
602    }
603    for (const auto& f : structType->fields()) {
604        this->writeModifiers(f.fModifiers, false);
605        this->writeType(*f.fType);
606        this->writeLine(" " + f.fName + ";");
607    }
608    fIndentation--;
609    this->write("}");
610    if (intf.fInstanceName.size()) {
611        this->write(" ");
612        this->write(intf.fInstanceName);
613        for (const auto& size : intf.fSizes) {
614            this->write("[");
615            if (size) {
616                this->writeExpression(*size, kTopLevel_Precedence);
617            }
618            this->write("]");
619        }
620    }
621    this->writeLine(";");
622}
623
624void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
625    ASSERT(decl.fVars.size() > 0);
626    this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
627    this->writeType(decl.fBaseType);
628    SkString separator(" ");
629    for (const auto& var : decl.fVars) {
630        ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
631        this->write(separator);
632        separator = SkString(", ");
633        this->write(var.fVar->fName);
634        for (const auto& size : var.fSizes) {
635            this->write("[");
636            if (size) {
637                this->writeExpression(*size, kTopLevel_Precedence);
638            }
639            this->write("]");
640        }
641        if (var.fValue) {
642            this->write(" = ");
643            this->writeExpression(*var.fValue, kTopLevel_Precedence);
644        }
645        if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
646            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
647                fHeader.writeText("#extension ");
648                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
649                fHeader.writeText(" : require\n");
650            }
651            fFoundImageDecl = true;
652        }
653    }
654    this->write(";");
655}
656
657void GLSLCodeGenerator::writeStatement(const Statement& s) {
658    switch (s.fKind) {
659        case Statement::kBlock_Kind:
660            this->writeBlock((Block&) s);
661            break;
662        case Statement::kExpression_Kind:
663            this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
664            this->write(";");
665            break;
666        case Statement::kReturn_Kind:
667            this->writeReturnStatement((ReturnStatement&) s);
668            break;
669        case Statement::kVarDeclarations_Kind:
670            this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
671            break;
672        case Statement::kIf_Kind:
673            this->writeIfStatement((IfStatement&) s);
674            break;
675        case Statement::kFor_Kind:
676            this->writeForStatement((ForStatement&) s);
677            break;
678        case Statement::kWhile_Kind:
679            this->writeWhileStatement((WhileStatement&) s);
680            break;
681        case Statement::kDo_Kind:
682            this->writeDoStatement((DoStatement&) s);
683            break;
684        case Statement::kSwitch_Kind:
685            this->writeSwitchStatement((SwitchStatement&) s);
686            break;
687        case Statement::kBreak_Kind:
688            this->write("break;");
689            break;
690        case Statement::kContinue_Kind:
691            this->write("continue;");
692            break;
693        case Statement::kDiscard_Kind:
694            this->write("discard;");
695            break;
696        default:
697            ABORT("unsupported statement: %s", s.description().c_str());
698    }
699}
700
701void GLSLCodeGenerator::writeBlock(const Block& b) {
702    this->writeLine("{");
703    fIndentation++;
704    for (const auto& s : b.fStatements) {
705        this->writeStatement(*s);
706        this->writeLine();
707    }
708    fIndentation--;
709    this->write("}");
710}
711
712void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
713    this->write("if (");
714    this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
715    this->write(") ");
716    this->writeStatement(*stmt.fIfTrue);
717    if (stmt.fIfFalse) {
718        this->write(" else ");
719        this->writeStatement(*stmt.fIfFalse);
720    }
721}
722
723void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
724    this->write("for (");
725    if (f.fInitializer) {
726        this->writeStatement(*f.fInitializer);
727    } else {
728        this->write("; ");
729    }
730    if (f.fTest) {
731        this->writeExpression(*f.fTest, kTopLevel_Precedence);
732    }
733    this->write("; ");
734    if (f.fNext) {
735        this->writeExpression(*f.fNext, kTopLevel_Precedence);
736    }
737    this->write(") ");
738    this->writeStatement(*f.fStatement);
739}
740
741void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
742    this->write("while (");
743    this->writeExpression(*w.fTest, kTopLevel_Precedence);
744    this->write(") ");
745    this->writeStatement(*w.fStatement);
746}
747
748void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
749    this->write("do ");
750    this->writeStatement(*d.fStatement);
751    this->write(" while (");
752    this->writeExpression(*d.fTest, kTopLevel_Precedence);
753    this->write(");");
754}
755
756void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
757    this->write("switch (");
758    this->writeExpression(*s.fValue, kTopLevel_Precedence);
759    this->writeLine(") {");
760    fIndentation++;
761    for (const auto& c : s.fCases) {
762        if (c->fValue) {
763            this->write("case ");
764            this->writeExpression(*c->fValue, kTopLevel_Precedence);
765            this->writeLine(":");
766        } else {
767            this->writeLine("default:");
768        }
769        fIndentation++;
770        for (const auto& stmt : c->fStatements) {
771            this->writeStatement(*stmt);
772            this->writeLine();
773        }
774        fIndentation--;
775    }
776    fIndentation--;
777    this->write("}");
778}
779
780void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
781    this->write("return");
782    if (r.fExpression) {
783        this->write(" ");
784        this->writeExpression(*r.fExpression, kTopLevel_Precedence);
785    }
786    this->write(";");
787}
788
789bool GLSLCodeGenerator::generateCode() {
790    SkWStream* rawOut = fOut;
791    fOut = &fHeader;
792    fProgramKind = fProgram.fKind;
793    this->write(fProgram.fSettings.fCaps->versionDeclString());
794    this->writeLine();
795    for (const auto& e : fProgram.fElements) {
796        if (e->fKind == ProgramElement::kExtension_Kind) {
797            this->writeExtension((Extension&) *e);
798        }
799    }
800    SkDynamicMemoryWStream body;
801    fOut = &body;
802    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
803        this->write("precision ");
804        switch (fProgram.fDefaultPrecision) {
805            case Modifiers::kLowp_Flag:
806                this->write("lowp");
807                break;
808            case Modifiers::kMediump_Flag:
809                this->write("mediump");
810                break;
811            case Modifiers::kHighp_Flag:
812                this->write("highp");
813                break;
814            default:
815                ASSERT(false);
816                this->write("<error>");
817        }
818        this->writeLine(" float;");
819    }
820    for (const auto& e : fProgram.fElements) {
821        switch (e->fKind) {
822            case ProgramElement::kExtension_Kind:
823                break;
824            case ProgramElement::kVar_Kind: {
825                VarDeclarations& decl = (VarDeclarations&) *e;
826                if (decl.fVars.size() > 0) {
827                    int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
828                    if (builtin == -1) {
829                        // normal var
830                        this->writeVarDeclarations(decl, true);
831                        this->writeLine();
832                    } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
833                               fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
834                        this->write("out ");
835                        if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
836                            this->write("mediump ");
837                        }
838                        this->writeLine("vec4 sk_FragColor;");
839                    }
840                }
841                break;
842            }
843            case ProgramElement::kInterfaceBlock_Kind:
844                this->writeInterfaceBlock((InterfaceBlock&) *e);
845                break;
846            case ProgramElement::kFunction_Kind:
847                this->writeFunction((FunctionDefinition&) *e);
848                break;
849            case ProgramElement::kModifiers_Kind:
850                this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
851                this->writeLine(";");
852                break;
853            default:
854                printf("%s\n", e->description().c_str());
855                ABORT("unsupported program element");
856        }
857    }
858    fOut = nullptr;
859
860    write_data(*fHeader.detachAsData(), *rawOut);
861    write_data(*body.detachAsData(), *rawOut);
862    return true;
863}
864
865}
866