• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
9 
10 #include "include/private/SkSLProgramElement.h"
11 #include "include/private/SkSLStatement.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLOperators.h"
14 #include "src/sksl/SkSLStringStream.h"
15 #include "src/sksl/ir/SkSLBinaryExpression.h"
16 #include "src/sksl/ir/SkSLChildCall.h"
17 #include "src/sksl/ir/SkSLConstructor.h"
18 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
19 #include "src/sksl/ir/SkSLDoStatement.h"
20 #include "src/sksl/ir/SkSLExpressionStatement.h"
21 #include "src/sksl/ir/SkSLFieldAccess.h"
22 #include "src/sksl/ir/SkSLForStatement.h"
23 #include "src/sksl/ir/SkSLFunctionCall.h"
24 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
25 #include "src/sksl/ir/SkSLFunctionDefinition.h"
26 #include "src/sksl/ir/SkSLFunctionPrototype.h"
27 #include "src/sksl/ir/SkSLIfStatement.h"
28 #include "src/sksl/ir/SkSLIndexExpression.h"
29 #include "src/sksl/ir/SkSLPostfixExpression.h"
30 #include "src/sksl/ir/SkSLPrefixExpression.h"
31 #include "src/sksl/ir/SkSLReturnStatement.h"
32 #include "src/sksl/ir/SkSLStructDefinition.h"
33 #include "src/sksl/ir/SkSLSwitchStatement.h"
34 #include "src/sksl/ir/SkSLSwizzle.h"
35 #include "src/sksl/ir/SkSLTernaryExpression.h"
36 #include "src/sksl/ir/SkSLVarDeclarations.h"
37 #include "src/sksl/ir/SkSLVariableReference.h"
38 
39 #include <unordered_map>
40 
41 #if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
42 
43 namespace SkSL {
44 namespace PipelineStage {
45 
46 class PipelineStageCodeGenerator {
47 public:
PipelineStageCodeGenerator(const Program & program,const char * sampleCoords,const char * inputColor,const char * destColor,Callbacks * callbacks)48     PipelineStageCodeGenerator(const Program& program,
49                                const char* sampleCoords,
50                                const char* inputColor,
51                                const char* destColor,
52                                Callbacks* callbacks)
53             : fProgram(program)
54             , fSampleCoords(sampleCoords)
55             , fInputColor(inputColor)
56             , fDestColor(destColor)
57             , fCallbacks(callbacks) {}
58 
59     void generateCode();
60 
61 private:
62     using Precedence = Operator::Precedence;
63 
64     void write(std::string_view s);
65     void writeLine(std::string_view s = std::string_view());
66 
67     std::string typeName(const Type& type);
68     void writeType(const Type& type);
69 
70     std::string functionName(const FunctionDeclaration& decl);
71     void writeFunction(const FunctionDefinition& f);
72     void writeFunctionDeclaration(const FunctionDeclaration& decl);
73 
74     std::string modifierString(const Modifiers& modifiers);
75     std::string functionDeclaration(const FunctionDeclaration& decl);
76 
77     // Handles arrays correctly, eg: `float x[2]`
78     std::string typedVariable(const Type& type, std::string_view name);
79 
80     void writeVarDeclaration(const VarDeclaration& var);
81     void writeGlobalVarDeclaration(const GlobalVarDeclaration& g);
82     void writeStructDefinition(const StructDefinition& s);
83 
84     void writeExpression(const Expression& expr, Precedence parentPrecedence);
85     void writeChildCall(const ChildCall& c);
86     void writeFunctionCall(const FunctionCall& c);
87     void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
88     void writeFieldAccess(const FieldAccess& f);
89     void writeSwizzle(const Swizzle& swizzle);
90     void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
91     void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
92     void writeIndexExpression(const IndexExpression& expr);
93     void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
94     void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
95     void writeVariableReference(const VariableReference& ref);
96 
97     void writeStatement(const Statement& s);
98     void writeBlock(const Block& b);
99     void writeIfStatement(const IfStatement& stmt);
100     void writeDoStatement(const DoStatement& d);
101     void writeForStatement(const ForStatement& f);
102     void writeReturnStatement(const ReturnStatement& r);
103     void writeSwitchStatement(const SwitchStatement& s);
104 
105     void writeProgramElementFirstPass(const ProgramElement& e);
106     void writeProgramElementSecondPass(const ProgramElement& e);
107 
108     struct AutoOutputBuffer {
AutoOutputBufferSkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer109         AutoOutputBuffer(PipelineStageCodeGenerator* generator) : fGenerator(generator) {
110             fOldBuffer = fGenerator->fBuffer;
111             fGenerator->fBuffer = &fBuffer;
112         }
113 
~AutoOutputBufferSkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer114         ~AutoOutputBuffer() {
115             fGenerator->fBuffer = fOldBuffer;
116         }
117 
118         PipelineStageCodeGenerator* fGenerator;
119         StringStream*               fOldBuffer;
120         StringStream                fBuffer;
121     };
122 
123     const Program& fProgram;
124     const char*    fSampleCoords;
125     const char*    fInputColor;
126     const char*    fDestColor;
127     Callbacks*     fCallbacks;
128 
129     std::unordered_map<const Variable*, std::string>            fVariableNames;
130     std::unordered_map<const FunctionDeclaration*, std::string> fFunctionNames;
131     std::unordered_map<const Type*, std::string>                fStructNames;
132 
133     StringStream* fBuffer = nullptr;
134     bool          fCastReturnsToHalf = false;
135 };
136 
137 
write(std::string_view s)138 void PipelineStageCodeGenerator::write(std::string_view s) {
139     fBuffer->write(s.data(), s.length());
140 }
141 
writeLine(std::string_view s)142 void PipelineStageCodeGenerator::writeLine(std::string_view s) {
143     fBuffer->write(s.data(), s.length());
144     fBuffer->writeText("\n");
145 }
146 
writeChildCall(const ChildCall & c)147 void PipelineStageCodeGenerator::writeChildCall(const ChildCall& c) {
148     const ExpressionArray& arguments = c.arguments();
149     SkASSERT(arguments.size() >= 1);
150     int index = 0;
151     bool found = false;
152     for (const ProgramElement* p : fProgram.elements()) {
153         if (p->is<GlobalVarDeclaration>()) {
154             const GlobalVarDeclaration& global = p->as<GlobalVarDeclaration>();
155             const VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
156             if (&decl.var() == &c.child()) {
157                 found = true;
158             } else if (decl.var().type().isEffectChild()) {
159                 ++index;
160             }
161         }
162         if (found) {
163             break;
164         }
165     }
166     SkASSERT(found);
167 
168     // Shaders require a coordinate argument. Color filters require a color argument.
169     // Blenders require two color arguments.
170     std::string sampleOutput;
171     {
172         AutoOutputBuffer exprBuffer(this);
173         this->writeExpression(*arguments[0], Precedence::kSequence);
174 
175         switch (c.child().type().typeKind()) {
176             case Type::TypeKind::kShader: {
177                 SkASSERT(arguments.size() == 1);
178                 SkASSERT(arguments[0]->type().matches(*fProgram.fContext->fTypes.fFloat2));
179                 sampleOutput = fCallbacks->sampleShader(index, exprBuffer.fBuffer.str());
180                 break;
181             }
182             case Type::TypeKind::kColorFilter: {
183                 SkASSERT(arguments.size() == 1);
184                 SkASSERT(arguments[0]->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
185                          arguments[0]->type().matches(*fProgram.fContext->fTypes.fFloat4));
186                 sampleOutput = fCallbacks->sampleColorFilter(index, exprBuffer.fBuffer.str());
187                 break;
188             }
189             case Type::TypeKind::kBlender: {
190                 SkASSERT(arguments.size() == 2);
191                 SkASSERT(arguments[0]->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
192                          arguments[0]->type().matches(*fProgram.fContext->fTypes.fFloat4));
193                 SkASSERT(arguments[1]->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
194                          arguments[1]->type().matches(*fProgram.fContext->fTypes.fFloat4));
195 
196                 AutoOutputBuffer exprBuffer2(this);
197                 this->writeExpression(*arguments[1], Precedence::kSequence);
198 
199                 sampleOutput = fCallbacks->sampleBlender(index, exprBuffer.fBuffer.str(),
200                                                                 exprBuffer2.fBuffer.str());
201                 break;
202             }
203             default: {
204                 SkDEBUGFAILF("cannot sample from type '%s'",
205                              c.child().type().description().c_str());
206             }
207         }
208     }
209     this->write(sampleOutput);
210     return;
211 }
212 
writeFunctionCall(const FunctionCall & c)213 void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
214     const FunctionDeclaration& function = c.function();
215 
216     if (function.intrinsicKind() == IntrinsicKind::k_toLinearSrgb_IntrinsicKind ||
217         function.intrinsicKind() == IntrinsicKind::k_fromLinearSrgb_IntrinsicKind) {
218         SkASSERT(c.arguments().size() == 1);
219         std::string colorArg;
220         {
221             AutoOutputBuffer exprBuffer(this);
222             this->writeExpression(*c.arguments()[0], Precedence::kSequence);
223             colorArg = exprBuffer.fBuffer.str();
224         }
225 
226         switch (function.intrinsicKind()) {
227             case IntrinsicKind::k_toLinearSrgb_IntrinsicKind:
228                 this->write(fCallbacks->toLinearSrgb(std::move(colorArg)));
229                 break;
230             case IntrinsicKind::k_fromLinearSrgb_IntrinsicKind:
231                 this->write(fCallbacks->fromLinearSrgb(std::move(colorArg)));
232                 break;
233             default:
234                 SkUNREACHABLE;
235         }
236 
237         return;
238     }
239 
240     if (function.isBuiltin()) {
241         this->write(function.name());
242     } else {
243         this->write(this->functionName(function));
244     }
245 
246     this->write("(");
247     const char* separator = "";
248     for (const auto& arg : c.arguments()) {
249         this->write(separator);
250         separator = ", ";
251         this->writeExpression(*arg, Precedence::kSequence);
252     }
253     this->write(")");
254 }
255 
writeVariableReference(const VariableReference & ref)256 void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
257     const Variable* var = ref.variable();
258     const Modifiers& modifiers = var->modifiers();
259 
260     if (modifiers.fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
261         this->write(fSampleCoords);
262         return;
263     } else if (modifiers.fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN) {
264         this->write(fInputColor);
265         return;
266     } else if (modifiers.fLayout.fBuiltin == SK_DEST_COLOR_BUILTIN) {
267         this->write(fDestColor);
268         return;
269     }
270 
271     auto it = fVariableNames.find(var);
272     if (it != fVariableNames.end()) {
273         this->write(it->second);
274     } else {
275         this->write(var->name());
276     }
277 }
278 
writeIfStatement(const IfStatement & stmt)279 void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& stmt) {
280     if (stmt.isStatic()) {
281         this->write("@");
282     }
283     this->write("if (");
284     this->writeExpression(*stmt.test(), Precedence::kTopLevel);
285     this->write(") ");
286     this->writeStatement(*stmt.ifTrue());
287     if (stmt.ifFalse()) {
288         this->write(" else ");
289         this->writeStatement(*stmt.ifFalse());
290     }
291 }
292 
writeReturnStatement(const ReturnStatement & r)293 void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
294     this->write("return");
295     if (r.expression()) {
296         this->write(" ");
297         if (fCastReturnsToHalf) {
298             this->write("half4(");
299         }
300         this->writeExpression(*r.expression(), Precedence::kTopLevel);
301         if (fCastReturnsToHalf) {
302             this->write(")");
303         }
304     }
305     this->write(";");
306 }
307 
writeSwitchStatement(const SwitchStatement & s)308 void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
309     this->write("switch (");
310     this->writeExpression(*s.value(), Precedence::kTopLevel);
311     this->writeLine(") {");
312     for (const std::unique_ptr<Statement>& stmt : s.cases()) {
313         const SwitchCase& c = stmt->as<SwitchCase>();
314         if (c.isDefault()) {
315             this->writeLine("default:");
316         } else {
317             this->write("case ");
318             this->write(std::to_string(c.value()));
319             this->writeLine(":");
320         }
321         if (!c.statement()->isEmpty()) {
322             this->writeStatement(*c.statement());
323             this->writeLine();
324         }
325     }
326     this->writeLine();
327     this->write("}");
328 }
329 
functionName(const FunctionDeclaration & decl)330 std::string PipelineStageCodeGenerator::functionName(const FunctionDeclaration& decl) {
331     if (decl.isMain()) {
332         return std::string(fCallbacks->getMainName());
333     }
334 
335     auto it = fFunctionNames.find(&decl);
336     if (it != fFunctionNames.end()) {
337         return it->second;
338     }
339 
340     std::string mangledName = fCallbacks->getMangledName(std::string(decl.name()).c_str());
341     fFunctionNames.insert({&decl, mangledName});
342     return mangledName;
343 }
344 
writeFunction(const FunctionDefinition & f)345 void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
346     AutoOutputBuffer body(this);
347 
348     // We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
349     // our code in the processor, the surrounding code is going to expect half4, so we
350     // explicitly cast any returns (from main) to half4. This is only strictly necessary
351     // if the return type is float4 - injecting it unconditionally reduces the risk of an
352     // obscure bug.
353     const FunctionDeclaration& decl = f.declaration();
354     if (decl.isMain() &&
355         fProgram.fConfig->fKind != SkSL::ProgramKind::kCustomMeshVertex &&
356         fProgram.fConfig->fKind != SkSL::ProgramKind::kCustomMeshFragment) {
357         fCastReturnsToHalf = true;
358     }
359 
360     for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
361         this->writeStatement(*stmt);
362         this->writeLine();
363     }
364 
365     if (decl.isMain()) {
366         fCastReturnsToHalf = false;
367     }
368 
369     fCallbacks->defineFunction(this->functionDeclaration(decl).c_str(),
370                                body.fBuffer.str().c_str(),
371                                decl.isMain());
372 }
373 
functionDeclaration(const FunctionDeclaration & decl)374 std::string PipelineStageCodeGenerator::functionDeclaration(const FunctionDeclaration& decl) {
375     // This is similar to decl.description(), but substitutes a mangled name, and handles modifiers
376     // on the function (e.g. `inline`) and its parameters (e.g. `inout`).
377     std::string declString =
378             String::printf("%s%s%s %s(",
379                            (decl.modifiers().fFlags & Modifiers::kInline_Flag) ? "inline " : "",
380                            (decl.modifiers().fFlags & Modifiers::kNoInline_Flag) ? "noinline " : "",
381                            this->typeName(decl.returnType()).c_str(),
382                            this->functionName(decl).c_str());
383     const char* separator = "";
384     for (const Variable* p : decl.parameters()) {
385         declString.append(separator);
386         declString.append(this->modifierString(p->modifiers()));
387         declString.append(this->typedVariable(p->type(), p->name()).c_str());
388         separator = ", ";
389     }
390 
391     return declString + ")";
392 }
393 
writeFunctionDeclaration(const FunctionDeclaration & decl)394 void PipelineStageCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& decl) {
395     if (!decl.isMain()) {
396         fCallbacks->declareFunction(this->functionDeclaration(decl).c_str());
397     }
398 }
399 
writeGlobalVarDeclaration(const GlobalVarDeclaration & g)400 void PipelineStageCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& g) {
401     const VarDeclaration& decl = g.declaration()->as<VarDeclaration>();
402     const Variable& var = decl.var();
403 
404     if (var.isBuiltin() || var.type().isOpaque()) {
405         // Don't re-declare these. (eg, sk_FragCoord, or fragmentProcessor children)
406     } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
407         std::string uniformName = fCallbacks->declareUniform(&decl);
408         fVariableNames.insert({&var, std::move(uniformName)});
409     } else {
410         std::string mangledName = fCallbacks->getMangledName(std::string(var.name()).c_str());
411         std::string declaration = this->modifierString(var.modifiers()) +
412                              this->typedVariable(var.type(),
413                                                  std::string_view(mangledName.c_str()));
414         if (decl.value()) {
415             AutoOutputBuffer outputToBuffer(this);
416             this->writeExpression(*decl.value(), Precedence::kTopLevel);
417             declaration += " = ";
418             declaration += outputToBuffer.fBuffer.str();
419         }
420         declaration += ";\n";
421         fCallbacks->declareGlobal(declaration.c_str());
422         fVariableNames.insert({&var, std::move(mangledName)});
423     }
424 }
425 
writeStructDefinition(const StructDefinition & s)426 void PipelineStageCodeGenerator::writeStructDefinition(const StructDefinition& s) {
427     const Type& type = s.type();
428     std::string mangledName = fCallbacks->getMangledName(type.displayName().c_str());
429     std::string definition = "struct " + mangledName + " {\n";
430     for (const auto& f : type.fields()) {
431         definition += this->typedVariable(*f.fType, f.fName) + ";\n";
432     }
433     definition += "};\n";
434     fStructNames.insert({&type, std::move(mangledName)});
435     fCallbacks->defineStruct(definition.c_str());
436 }
437 
writeProgramElementFirstPass(const ProgramElement & e)438 void PipelineStageCodeGenerator::writeProgramElementFirstPass(const ProgramElement& e) {
439     switch (e.kind()) {
440         case ProgramElement::Kind::kGlobalVar:
441             this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
442             break;
443         case ProgramElement::Kind::kFunction:
444             this->writeFunctionDeclaration(e.as<FunctionDefinition>().declaration());
445             break;
446         case ProgramElement::Kind::kFunctionPrototype:
447             // Skip this; we're already emitting prototypes for every FunctionDefinition.
448             // (See case kFunction, directly above.)
449             break;
450         case ProgramElement::Kind::kStructDefinition:
451             this->writeStructDefinition(e.as<StructDefinition>());
452             break;
453 
454         case ProgramElement::Kind::kExtension:
455         case ProgramElement::Kind::kInterfaceBlock:
456         case ProgramElement::Kind::kModifiers:
457         default:
458             SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
459             break;
460     }
461 }
462 
writeProgramElementSecondPass(const ProgramElement & e)463 void PipelineStageCodeGenerator::writeProgramElementSecondPass(const ProgramElement& e) {
464     if (e.is<FunctionDefinition>()) {
465         this->writeFunction(e.as<FunctionDefinition>());
466     }
467 }
468 
typeName(const Type & raw)469 std::string PipelineStageCodeGenerator::typeName(const Type& raw) {
470     const Type& type = raw.resolve();
471     if (type.isArray()) {
472         // This is necessary so that name mangling on arrays-of-structs works properly.
473         std::string arrayName = this->typeName(type.componentType());
474         arrayName.push_back('[');
475         arrayName += std::to_string(type.columns());
476         arrayName.push_back(']');
477         return arrayName;
478     }
479 
480     auto it = fStructNames.find(&type);
481     return it != fStructNames.end() ? it->second : std::string(type.name());
482 }
483 
writeType(const Type & type)484 void PipelineStageCodeGenerator::writeType(const Type& type) {
485     this->write(this->typeName(type));
486 }
487 
writeExpression(const Expression & expr,Precedence parentPrecedence)488 void PipelineStageCodeGenerator::writeExpression(const Expression& expr,
489                                                  Precedence parentPrecedence) {
490     switch (expr.kind()) {
491         case Expression::Kind::kBinary:
492             this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
493             break;
494         case Expression::Kind::kLiteral:
495             this->write(expr.description());
496             break;
497         case Expression::Kind::kChildCall:
498             this->writeChildCall(expr.as<ChildCall>());
499             break;
500         case Expression::Kind::kConstructorArray:
501         case Expression::Kind::kConstructorArrayCast:
502         case Expression::Kind::kConstructorCompound:
503         case Expression::Kind::kConstructorCompoundCast:
504         case Expression::Kind::kConstructorDiagonalMatrix:
505         case Expression::Kind::kConstructorMatrixResize:
506         case Expression::Kind::kConstructorScalarCast:
507         case Expression::Kind::kConstructorSplat:
508         case Expression::Kind::kConstructorStruct:
509             this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
510             break;
511         case Expression::Kind::kFieldAccess:
512             this->writeFieldAccess(expr.as<FieldAccess>());
513             break;
514         case Expression::Kind::kFunctionCall:
515             this->writeFunctionCall(expr.as<FunctionCall>());
516             break;
517         case Expression::Kind::kPrefix:
518             this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
519             break;
520         case Expression::Kind::kPostfix:
521             this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
522             break;
523         case Expression::Kind::kSwizzle:
524             this->writeSwizzle(expr.as<Swizzle>());
525             break;
526         case Expression::Kind::kVariableReference:
527             this->writeVariableReference(expr.as<VariableReference>());
528             break;
529         case Expression::Kind::kTernary:
530             this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
531             break;
532         case Expression::Kind::kIndex:
533             this->writeIndexExpression(expr.as<IndexExpression>());
534             break;
535         case Expression::Kind::kSetting:
536         default:
537             SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
538             break;
539     }
540 }
541 
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)542 void PipelineStageCodeGenerator::writeAnyConstructor(const AnyConstructor& c,
543                                                      Precedence parentPrecedence) {
544     this->writeType(c.type());
545     this->write("(");
546     const char* separator = "";
547     for (const auto& arg : c.argumentSpan()) {
548         this->write(separator);
549         separator = ", ";
550         this->writeExpression(*arg, Precedence::kSequence);
551     }
552     this->write(")");
553 }
554 
writeIndexExpression(const IndexExpression & expr)555 void PipelineStageCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
556     this->writeExpression(*expr.base(), Precedence::kPostfix);
557     this->write("[");
558     this->writeExpression(*expr.index(), Precedence::kTopLevel);
559     this->write("]");
560 }
561 
writeFieldAccess(const FieldAccess & f)562 void PipelineStageCodeGenerator::writeFieldAccess(const FieldAccess& f) {
563     if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
564         this->writeExpression(*f.base(), Precedence::kPostfix);
565         this->write(".");
566     }
567     const Type& baseType = f.base()->type();
568     this->write(baseType.fields()[f.fieldIndex()].fName);
569 }
570 
writeSwizzle(const Swizzle & swizzle)571 void PipelineStageCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
572     this->writeExpression(*swizzle.base(), Precedence::kPostfix);
573     this->write(".");
574     for (int c : swizzle.components()) {
575         SkASSERT(c >= 0 && c <= 3);
576         this->write(&("x\0y\0z\0w\0"[c * 2]));
577     }
578 }
579 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)580 void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
581                                                        Precedence parentPrecedence) {
582     const Expression& left = *b.left();
583     const Expression& right = *b.right();
584     Operator op = b.getOperator();
585 
586     Precedence precedence = op.getBinaryPrecedence();
587     if (precedence >= parentPrecedence) {
588         this->write("(");
589     }
590     this->writeExpression(left, precedence);
591     this->write(op.operatorName());
592     this->writeExpression(right, precedence);
593     if (precedence >= parentPrecedence) {
594         this->write(")");
595     }
596 }
597 
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)598 void PipelineStageCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
599                                                         Precedence parentPrecedence) {
600     if (Precedence::kTernary >= parentPrecedence) {
601         this->write("(");
602     }
603     this->writeExpression(*t.test(), Precedence::kTernary);
604     this->write(" ? ");
605     this->writeExpression(*t.ifTrue(), Precedence::kTernary);
606     this->write(" : ");
607     this->writeExpression(*t.ifFalse(), Precedence::kTernary);
608     if (Precedence::kTernary >= parentPrecedence) {
609         this->write(")");
610     }
611 }
612 
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)613 void PipelineStageCodeGenerator::writePrefixExpression(const PrefixExpression& p,
614                                                        Precedence parentPrecedence) {
615     if (Precedence::kPrefix >= parentPrecedence) {
616         this->write("(");
617     }
618     this->write(p.getOperator().tightOperatorName());
619     this->writeExpression(*p.operand(), Precedence::kPrefix);
620     if (Precedence::kPrefix >= parentPrecedence) {
621         this->write(")");
622     }
623 }
624 
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)625 void PipelineStageCodeGenerator::writePostfixExpression(const PostfixExpression& p,
626                                                         Precedence parentPrecedence) {
627     if (Precedence::kPostfix >= parentPrecedence) {
628         this->write("(");
629     }
630     this->writeExpression(*p.operand(), Precedence::kPostfix);
631     this->write(p.getOperator().tightOperatorName());
632     if (Precedence::kPostfix >= parentPrecedence) {
633         this->write(")");
634     }
635 }
636 
modifierString(const Modifiers & modifiers)637 std::string PipelineStageCodeGenerator::modifierString(const Modifiers& modifiers) {
638     std::string result;
639     if (modifiers.fFlags & Modifiers::kConst_Flag) {
640         result.append("const ");
641     }
642 
643     if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kOut_Flag)) {
644         result.append("inout ");
645     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
646         result.append("in ");
647     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
648         result.append("out ");
649     }
650 
651     return result;
652 }
653 
typedVariable(const Type & type,std::string_view name)654 std::string PipelineStageCodeGenerator::typedVariable(const Type& type, std::string_view name) {
655     const Type& baseType = type.isArray() ? type.componentType() : type;
656 
657     std::string decl = this->typeName(baseType) + " " + std::string(name);
658     if (type.isArray()) {
659         decl += "[" + std::to_string(type.columns()) + "]";
660     }
661     return decl;
662 }
663 
writeVarDeclaration(const VarDeclaration & var)664 void PipelineStageCodeGenerator::writeVarDeclaration(const VarDeclaration& var) {
665     this->write(this->modifierString(var.var().modifiers()));
666     this->write(this->typedVariable(var.var().type(), var.var().name()));
667     if (var.value()) {
668         this->write(" = ");
669         this->writeExpression(*var.value(), Precedence::kTopLevel);
670     }
671     this->write(";");
672 }
673 
writeStatement(const Statement & s)674 void PipelineStageCodeGenerator::writeStatement(const Statement& s) {
675     switch (s.kind()) {
676         case Statement::Kind::kBlock:
677             this->writeBlock(s.as<Block>());
678             break;
679         case Statement::Kind::kBreak:
680             this->write("break;");
681             break;
682         case Statement::Kind::kContinue:
683             this->write("continue;");
684             break;
685         case Statement::Kind::kExpression:
686             this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
687             this->write(";");
688             break;
689         case Statement::Kind::kDo:
690             this->writeDoStatement(s.as<DoStatement>());
691             break;
692         case Statement::Kind::kFor:
693             this->writeForStatement(s.as<ForStatement>());
694             break;
695         case Statement::Kind::kIf:
696             this->writeIfStatement(s.as<IfStatement>());
697             break;
698         case Statement::Kind::kReturn:
699             this->writeReturnStatement(s.as<ReturnStatement>());
700             break;
701         case Statement::Kind::kSwitch:
702             this->writeSwitchStatement(s.as<SwitchStatement>());
703             break;
704         case Statement::Kind::kVarDeclaration:
705             this->writeVarDeclaration(s.as<VarDeclaration>());
706             break;
707         case Statement::Kind::kDiscard:
708             SkDEBUGFAIL("Unsupported control flow");
709             break;
710         case Statement::Kind::kInlineMarker:
711         case Statement::Kind::kNop:
712             this->write(";");
713             break;
714         default:
715             SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
716             break;
717     }
718 }
719 
writeBlock(const Block & b)720 void PipelineStageCodeGenerator::writeBlock(const Block& b) {
721     // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
722     // something here to make the code valid).
723     bool isScope = b.isScope() || b.isEmpty();
724     if (isScope) {
725         this->writeLine("{");
726     }
727     for (const std::unique_ptr<Statement>& stmt : b.children()) {
728         if (!stmt->isEmpty()) {
729             this->writeStatement(*stmt);
730             this->writeLine();
731         }
732     }
733     if (isScope) {
734         this->write("}");
735     }
736 }
737 
writeDoStatement(const DoStatement & d)738 void PipelineStageCodeGenerator::writeDoStatement(const DoStatement& d) {
739     this->write("do ");
740     this->writeStatement(*d.statement());
741     this->write(" while (");
742     this->writeExpression(*d.test(), Precedence::kTopLevel);
743     this->write(");");
744     return;
745 }
746 
writeForStatement(const ForStatement & f)747 void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
748     // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
749     if (!f.initializer() && f.test() && !f.next()) {
750         this->write("while (");
751         this->writeExpression(*f.test(), Precedence::kTopLevel);
752         this->write(") ");
753         this->writeStatement(*f.statement());
754         return;
755     }
756 
757     this->write("for (");
758     if (f.initializer() && !f.initializer()->isEmpty()) {
759         this->writeStatement(*f.initializer());
760     } else {
761         this->write("; ");
762     }
763     if (f.test()) {
764         this->writeExpression(*f.test(), Precedence::kTopLevel);
765     }
766     this->write("; ");
767     if (f.next()) {
768         this->writeExpression(*f.next(), Precedence::kTopLevel);
769     }
770     this->write(") ");
771     this->writeStatement(*f.statement());
772 }
773 
generateCode()774 void PipelineStageCodeGenerator::generateCode() {
775     // Write all the program elements except for functions; prototype all the functions.
776     for (const ProgramElement* e : fProgram.elements()) {
777         this->writeProgramElementFirstPass(*e);
778     }
779 
780     // We always place FunctionDefinition elements last, because the inliner likes to move function
781     // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
782     // that the code relies on.
783     for (const ProgramElement* e : fProgram.elements()) {
784         this->writeProgramElementSecondPass(*e);
785     }
786 }
787 
ConvertProgram(const Program & program,const char * sampleCoords,const char * inputColor,const char * destColor,Callbacks * callbacks)788 void ConvertProgram(const Program& program,
789                     const char* sampleCoords,
790                     const char* inputColor,
791                     const char* destColor,
792                     Callbacks* callbacks) {
793     PipelineStageCodeGenerator generator(program, sampleCoords, inputColor, destColor, callbacks);
794     generator.generateCode();
795 }
796 
797 }  // namespace PipelineStage
798 }  // namespace SkSL
799 
800 #endif
801