• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 namespace SkSL {
22 
write(const char * s)23 void 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 
writeLine(const char * s)36 void GLSLCodeGenerator::writeLine(const char* s) {
37     this->write(s);
38     fOut->writeText("\n");
39     fAtLineStart = true;
40 }
41 
write(const SkString & s)42 void GLSLCodeGenerator::write(const SkString& s) {
43     this->write(s.c_str());
44 }
45 
writeLine(const SkString & s)46 void GLSLCodeGenerator::writeLine(const SkString& s) {
47     this->writeLine(s.c_str());
48 }
49 
writeLine()50 void GLSLCodeGenerator::writeLine() {
51     this->writeLine("");
52 }
53 
writeExtension(const Extension & ext)54 void GLSLCodeGenerator::writeExtension(const Extension& ext) {
55     this->writeLine("#extension " + ext.fName + " : enable");
56 }
57 
writeType(const Type & type)58 void 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 
writeExpression(const Expression & expr,Precedence parentPrecedence)83 void 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 
is_abs(Expression & expr)129 static 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.
writeMinAbsHack(Expression & absExpr,Expression & otherExpr)138 void 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 
writeFunctionCall(const FunctionCall & c)151 void 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 
writeConstructor(const Constructor & c)259 void 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 
writeFragCoord()270 void 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 
writeVariableReference(const VariableReference & ref)317 void 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 
writeIndexExpression(const IndexExpression & expr)346 void 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 
writeFieldAccess(const FieldAccess & f)353 void 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 
writeSwizzle(const Swizzle & swizzle)367 void 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 
get_binary_precedence(Token::Kind op)375 static 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 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)414 void 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 
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)428 void 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 
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)443 void 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 
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)455 void 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 
writeBoolLiteral(const BoolLiteral & b)467 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
468     this->write(b.fValue ? "true" : "false");
469 }
470 
writeIntLiteral(const IntLiteral & i)471 void 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 
writeFloatLiteral(const FloatLiteral & f)479 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
480     this->write(to_string(f.fValue));
481 }
482 
writeFunction(const FunctionDefinition & f)483 void 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 
writeModifiers(const Modifiers & modifiers,bool globalContext)527 void 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 
writeInterfaceBlock(const InterfaceBlock & intf)592 void 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 
writeVarDeclarations(const VarDeclarations & decl,bool global)624 void 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 
writeStatement(const Statement & s)657 void 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 
writeBlock(const Block & b)701 void 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 
writeIfStatement(const IfStatement & stmt)712 void 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 
writeForStatement(const ForStatement & f)723 void 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 
writeWhileStatement(const WhileStatement & w)741 void 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 
writeDoStatement(const DoStatement & d)748 void 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 
writeSwitchStatement(const SwitchStatement & s)756 void 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 
writeReturnStatement(const ReturnStatement & r)780 void 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 
generateCode()789 bool 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