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