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