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(skstd::string_view s);
65 void writeLine(skstd::string_view s = skstd::string_view());
66
67 String typeName(const Type& type);
68 void writeType(const Type& type);
69
70 String functionName(const FunctionDeclaration& decl);
71 void writeFunction(const FunctionDefinition& f);
72 void writeFunctionDeclaration(const FunctionDeclaration& decl);
73
74 String modifierString(const Modifiers& modifiers);
75 String functionDeclaration(const FunctionDeclaration& decl);
76
77 // Handles arrays correctly, eg: `float x[2]`
78 String typedVariable(const Type& type, skstd::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*, String> fVariableNames;
130 std::unordered_map<const FunctionDeclaration*, String> fFunctionNames;
131 std::unordered_map<const Type*, String> fStructNames;
132
133 StringStream* fBuffer = nullptr;
134 bool fCastReturnsToHalf = false;
135 };
136
137
write(skstd::string_view s)138 void PipelineStageCodeGenerator::write(skstd::string_view s) {
139 fBuffer->write(s.data(), s.length());
140 }
141
writeLine(skstd::string_view s)142 void PipelineStageCodeGenerator::writeLine(skstd::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 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() == *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() == *fProgram.fContext->fTypes.fHalf4 ||
185 arguments[0]->type() == *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() == *fProgram.fContext->fTypes.fHalf4 ||
192 arguments[0]->type() == *fProgram.fContext->fTypes.fFloat4);
193 SkASSERT(arguments[1]->type() == *fProgram.fContext->fTypes.fHalf4 ||
194 arguments[1]->type() == *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.isBuiltin()) {
217 this->write(function.name());
218 } else {
219 this->write(this->functionName(function));
220 }
221
222 this->write("(");
223 const char* separator = "";
224 for (const auto& arg : c.arguments()) {
225 this->write(separator);
226 separator = ", ";
227 this->writeExpression(*arg, Precedence::kSequence);
228 }
229 this->write(")");
230 }
231
writeVariableReference(const VariableReference & ref)232 void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
233 const Variable* var = ref.variable();
234 const Modifiers& modifiers = var->modifiers();
235
236 if (modifiers.fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
237 this->write(fSampleCoords);
238 return;
239 } else if (modifiers.fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN) {
240 this->write(fInputColor);
241 return;
242 } else if (modifiers.fLayout.fBuiltin == SK_DEST_COLOR_BUILTIN) {
243 this->write(fDestColor);
244 return;
245 }
246
247 auto it = fVariableNames.find(var);
248 if (it != fVariableNames.end()) {
249 this->write(it->second);
250 } else {
251 this->write(var->name());
252 }
253 }
254
writeIfStatement(const IfStatement & stmt)255 void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& stmt) {
256 if (stmt.isStatic()) {
257 this->write("@");
258 }
259 this->write("if (");
260 this->writeExpression(*stmt.test(), Precedence::kTopLevel);
261 this->write(") ");
262 this->writeStatement(*stmt.ifTrue());
263 if (stmt.ifFalse()) {
264 this->write(" else ");
265 this->writeStatement(*stmt.ifFalse());
266 }
267 }
268
writeReturnStatement(const ReturnStatement & r)269 void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
270 this->write("return");
271 if (r.expression()) {
272 this->write(" ");
273 if (fCastReturnsToHalf) {
274 this->write("half4(");
275 }
276 this->writeExpression(*r.expression(), Precedence::kTopLevel);
277 if (fCastReturnsToHalf) {
278 this->write(")");
279 }
280 }
281 this->write(";");
282 }
283
writeSwitchStatement(const SwitchStatement & s)284 void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
285 this->write("switch (");
286 this->writeExpression(*s.value(), Precedence::kTopLevel);
287 this->writeLine(") {");
288 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
289 const SwitchCase& c = stmt->as<SwitchCase>();
290 if (c.value()) {
291 this->write("case ");
292 this->writeExpression(*c.value(), Precedence::kTopLevel);
293 this->writeLine(":");
294 } else {
295 this->writeLine("default:");
296 }
297 if (!c.statement()->isEmpty()) {
298 this->writeStatement(*c.statement());
299 this->writeLine();
300 }
301 }
302 this->writeLine();
303 this->write("}");
304 }
305
functionName(const FunctionDeclaration & decl)306 String PipelineStageCodeGenerator::functionName(const FunctionDeclaration& decl) {
307 if (decl.isMain()) {
308 return String(decl.name());
309 }
310
311 auto it = fFunctionNames.find(&decl);
312 if (it != fFunctionNames.end()) {
313 return it->second;
314 }
315
316 String mangledName = fCallbacks->getMangledName(String(decl.name()).c_str());
317 fFunctionNames.insert({&decl, mangledName});
318 return mangledName;
319 }
320
writeFunction(const FunctionDefinition & f)321 void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
322 AutoOutputBuffer body(this);
323
324 // We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
325 // our code in the processor, the surrounding code is going to expect half4, so we
326 // explicitly cast any returns (from main) to half4. This is only strictly necessary
327 // if the return type is float4 - injecting it unconditionally reduces the risk of an
328 // obscure bug.
329 const FunctionDeclaration& decl = f.declaration();
330 if (decl.isMain()) {
331 fCastReturnsToHalf = true;
332 }
333
334 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
335 this->writeStatement(*stmt);
336 this->writeLine();
337 }
338
339 if (decl.isMain()) {
340 fCastReturnsToHalf = false;
341 }
342
343 fCallbacks->defineFunction(this->functionDeclaration(decl).c_str(),
344 body.fBuffer.str().c_str(),
345 decl.isMain());
346 }
347
functionDeclaration(const FunctionDeclaration & decl)348 String PipelineStageCodeGenerator::functionDeclaration(const FunctionDeclaration& decl) {
349 // This is similar to decl.description(), but substitutes a mangled name, and handles modifiers
350 // on the function (e.g. `inline`) and its parameters (e.g. `inout`).
351 String declString =
352 String::printf("%s%s%s %s(",
353 (decl.modifiers().fFlags & Modifiers::kInline_Flag) ? "inline " : "",
354 (decl.modifiers().fFlags & Modifiers::kNoInline_Flag) ? "noinline " : "",
355 this->typeName(decl.returnType()).c_str(),
356 this->functionName(decl).c_str());
357 const char* separator = "";
358 for (const Variable* p : decl.parameters()) {
359 declString.append(separator);
360 declString.append(this->modifierString(p->modifiers()));
361 declString.append(this->typedVariable(p->type(), p->name()).c_str());
362 separator = ", ";
363 }
364
365 return declString + ")";
366 }
367
writeFunctionDeclaration(const FunctionDeclaration & decl)368 void PipelineStageCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& decl) {
369 if (!decl.isMain()) {
370 fCallbacks->declareFunction(this->functionDeclaration(decl).c_str());
371 }
372 }
373
writeGlobalVarDeclaration(const GlobalVarDeclaration & g)374 void PipelineStageCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& g) {
375 const VarDeclaration& decl = g.declaration()->as<VarDeclaration>();
376 const Variable& var = decl.var();
377
378 if (var.isBuiltin() || var.type().isOpaque()) {
379 // Don't re-declare these. (eg, sk_FragCoord, or fragmentProcessor children)
380 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
381 String uniformName = fCallbacks->declareUniform(&decl);
382 fVariableNames.insert({&var, std::move(uniformName)});
383 } else {
384 String mangledName = fCallbacks->getMangledName(String(var.name()).c_str());
385 String declaration = this->modifierString(var.modifiers()) +
386 this->typedVariable(var.type(),
387 skstd::string_view(mangledName.c_str()));
388 if (decl.value()) {
389 AutoOutputBuffer outputToBuffer(this);
390 this->writeExpression(*decl.value(), Precedence::kTopLevel);
391 declaration += " = ";
392 declaration += outputToBuffer.fBuffer.str();
393 }
394 declaration += ";\n";
395 fCallbacks->declareGlobal(declaration.c_str());
396 fVariableNames.insert({&var, std::move(mangledName)});
397 }
398 }
399
writeStructDefinition(const StructDefinition & s)400 void PipelineStageCodeGenerator::writeStructDefinition(const StructDefinition& s) {
401 const Type& type = s.type();
402 String mangledName = fCallbacks->getMangledName(String(type.name()).c_str());
403 String definition = "struct " + mangledName + " {\n";
404 for (const auto& f : type.fields()) {
405 definition += this->typedVariable(*f.fType, f.fName) + ";\n";
406 }
407 definition += "};\n";
408 fStructNames.insert({&type, std::move(mangledName)});
409 fCallbacks->defineStruct(definition.c_str());
410 }
411
writeProgramElementFirstPass(const ProgramElement & e)412 void PipelineStageCodeGenerator::writeProgramElementFirstPass(const ProgramElement& e) {
413 switch (e.kind()) {
414 case ProgramElement::Kind::kGlobalVar:
415 this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
416 break;
417 case ProgramElement::Kind::kFunction:
418 this->writeFunctionDeclaration(e.as<FunctionDefinition>().declaration());
419 break;
420 case ProgramElement::Kind::kFunctionPrototype:
421 // Skip this; we're already emitting prototypes for every FunctionDefinition.
422 // (See case kFunction, directly above.)
423 break;
424 case ProgramElement::Kind::kStructDefinition:
425 this->writeStructDefinition(e.as<StructDefinition>());
426 break;
427
428 case ProgramElement::Kind::kExtension:
429 case ProgramElement::Kind::kInterfaceBlock:
430 case ProgramElement::Kind::kModifiers:
431 default:
432 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
433 break;
434 }
435 }
436
writeProgramElementSecondPass(const ProgramElement & e)437 void PipelineStageCodeGenerator::writeProgramElementSecondPass(const ProgramElement& e) {
438 if (e.is<FunctionDefinition>()) {
439 this->writeFunction(e.as<FunctionDefinition>());
440 }
441 }
442
typeName(const Type & type)443 String PipelineStageCodeGenerator::typeName(const Type& type) {
444 if (type.isArray()) {
445 // This is necessary so that name mangling on arrays-of-structs works properly.
446 String arrayName = this->typeName(type.componentType());
447 arrayName.push_back('[');
448 arrayName += to_string(type.columns());
449 arrayName.push_back(']');
450 return arrayName;
451 }
452
453 auto it = fStructNames.find(&type);
454 return it != fStructNames.end() ? it->second : String(type.name());
455 }
456
writeType(const Type & type)457 void PipelineStageCodeGenerator::writeType(const Type& type) {
458 this->write(this->typeName(type));
459 }
460
writeExpression(const Expression & expr,Precedence parentPrecedence)461 void PipelineStageCodeGenerator::writeExpression(const Expression& expr,
462 Precedence parentPrecedence) {
463 switch (expr.kind()) {
464 case Expression::Kind::kBinary:
465 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
466 break;
467 case Expression::Kind::kLiteral:
468 this->write(expr.description());
469 break;
470 case Expression::Kind::kChildCall:
471 this->writeChildCall(expr.as<ChildCall>());
472 break;
473 case Expression::Kind::kConstructorArray:
474 case Expression::Kind::kConstructorArrayCast:
475 case Expression::Kind::kConstructorCompound:
476 case Expression::Kind::kConstructorCompoundCast:
477 case Expression::Kind::kConstructorDiagonalMatrix:
478 case Expression::Kind::kConstructorMatrixResize:
479 case Expression::Kind::kConstructorScalarCast:
480 case Expression::Kind::kConstructorSplat:
481 case Expression::Kind::kConstructorStruct:
482 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
483 break;
484 case Expression::Kind::kFieldAccess:
485 this->writeFieldAccess(expr.as<FieldAccess>());
486 break;
487 case Expression::Kind::kFunctionCall:
488 this->writeFunctionCall(expr.as<FunctionCall>());
489 break;
490 case Expression::Kind::kPrefix:
491 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
492 break;
493 case Expression::Kind::kPostfix:
494 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
495 break;
496 case Expression::Kind::kSwizzle:
497 this->writeSwizzle(expr.as<Swizzle>());
498 break;
499 case Expression::Kind::kVariableReference:
500 this->writeVariableReference(expr.as<VariableReference>());
501 break;
502 case Expression::Kind::kTernary:
503 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
504 break;
505 case Expression::Kind::kIndex:
506 this->writeIndexExpression(expr.as<IndexExpression>());
507 break;
508 case Expression::Kind::kSetting:
509 default:
510 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
511 break;
512 }
513 }
514
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)515 void PipelineStageCodeGenerator::writeAnyConstructor(const AnyConstructor& c,
516 Precedence parentPrecedence) {
517 this->writeType(c.type());
518 this->write("(");
519 const char* separator = "";
520 for (const auto& arg : c.argumentSpan()) {
521 this->write(separator);
522 separator = ", ";
523 this->writeExpression(*arg, Precedence::kSequence);
524 }
525 this->write(")");
526 }
527
writeIndexExpression(const IndexExpression & expr)528 void PipelineStageCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
529 this->writeExpression(*expr.base(), Precedence::kPostfix);
530 this->write("[");
531 this->writeExpression(*expr.index(), Precedence::kTopLevel);
532 this->write("]");
533 }
534
writeFieldAccess(const FieldAccess & f)535 void PipelineStageCodeGenerator::writeFieldAccess(const FieldAccess& f) {
536 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
537 this->writeExpression(*f.base(), Precedence::kPostfix);
538 this->write(".");
539 }
540 const Type& baseType = f.base()->type();
541 this->write(baseType.fields()[f.fieldIndex()].fName);
542 }
543
writeSwizzle(const Swizzle & swizzle)544 void PipelineStageCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
545 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
546 this->write(".");
547 for (int c : swizzle.components()) {
548 SkASSERT(c >= 0 && c <= 3);
549 this->write(&("x\0y\0z\0w\0"[c * 2]));
550 }
551 }
552
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)553 void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
554 Precedence parentPrecedence) {
555 const Expression& left = *b.left();
556 const Expression& right = *b.right();
557 Operator op = b.getOperator();
558
559 Precedence precedence = op.getBinaryPrecedence();
560 if (precedence >= parentPrecedence) {
561 this->write("(");
562 }
563 this->writeExpression(left, precedence);
564 this->write(" ");
565 this->write(op.operatorName());
566 this->write(" ");
567 this->writeExpression(right, precedence);
568 if (precedence >= parentPrecedence) {
569 this->write(")");
570 }
571 }
572
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)573 void PipelineStageCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
574 Precedence parentPrecedence) {
575 if (Precedence::kTernary >= parentPrecedence) {
576 this->write("(");
577 }
578 this->writeExpression(*t.test(), Precedence::kTernary);
579 this->write(" ? ");
580 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
581 this->write(" : ");
582 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
583 if (Precedence::kTernary >= parentPrecedence) {
584 this->write(")");
585 }
586 }
587
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)588 void PipelineStageCodeGenerator::writePrefixExpression(const PrefixExpression& p,
589 Precedence parentPrecedence) {
590 if (Precedence::kPrefix >= parentPrecedence) {
591 this->write("(");
592 }
593 this->write(p.getOperator().operatorName());
594 this->writeExpression(*p.operand(), Precedence::kPrefix);
595 if (Precedence::kPrefix >= parentPrecedence) {
596 this->write(")");
597 }
598 }
599
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)600 void PipelineStageCodeGenerator::writePostfixExpression(const PostfixExpression& p,
601 Precedence parentPrecedence) {
602 if (Precedence::kPostfix >= parentPrecedence) {
603 this->write("(");
604 }
605 this->writeExpression(*p.operand(), Precedence::kPostfix);
606 this->write(p.getOperator().operatorName());
607 if (Precedence::kPostfix >= parentPrecedence) {
608 this->write(")");
609 }
610 }
611
modifierString(const Modifiers & modifiers)612 String PipelineStageCodeGenerator::modifierString(const Modifiers& modifiers) {
613 String result;
614 if (modifiers.fFlags & Modifiers::kConst_Flag) {
615 result.append("const ");
616 }
617
618 if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kOut_Flag)) {
619 result.append("inout ");
620 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
621 result.append("in ");
622 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
623 result.append("out ");
624 }
625
626 return result;
627 }
628
typedVariable(const Type & type,skstd::string_view name)629 String PipelineStageCodeGenerator::typedVariable(const Type& type, skstd::string_view name) {
630 const Type& baseType = type.isArray() ? type.componentType() : type;
631
632 String decl = this->typeName(baseType) + " " + name;
633 if (type.isArray()) {
634 decl += "[" + to_string(type.columns()) + "]";
635 }
636 return decl;
637 }
638
writeVarDeclaration(const VarDeclaration & var)639 void PipelineStageCodeGenerator::writeVarDeclaration(const VarDeclaration& var) {
640 this->write(this->modifierString(var.var().modifiers()));
641 this->write(this->typedVariable(var.var().type(), var.var().name()));
642 if (var.value()) {
643 this->write(" = ");
644 this->writeExpression(*var.value(), Precedence::kTopLevel);
645 }
646 this->write(";");
647 }
648
writeStatement(const Statement & s)649 void PipelineStageCodeGenerator::writeStatement(const Statement& s) {
650 switch (s.kind()) {
651 case Statement::Kind::kBlock:
652 this->writeBlock(s.as<Block>());
653 break;
654 case Statement::Kind::kBreak:
655 this->write("break;");
656 break;
657 case Statement::Kind::kContinue:
658 this->write("continue;");
659 break;
660 case Statement::Kind::kExpression:
661 this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
662 this->write(";");
663 break;
664 case Statement::Kind::kDo:
665 this->writeDoStatement(s.as<DoStatement>());
666 break;
667 case Statement::Kind::kFor:
668 this->writeForStatement(s.as<ForStatement>());
669 break;
670 case Statement::Kind::kIf:
671 this->writeIfStatement(s.as<IfStatement>());
672 break;
673 case Statement::Kind::kReturn:
674 this->writeReturnStatement(s.as<ReturnStatement>());
675 break;
676 case Statement::Kind::kSwitch:
677 this->writeSwitchStatement(s.as<SwitchStatement>());
678 break;
679 case Statement::Kind::kVarDeclaration:
680 this->writeVarDeclaration(s.as<VarDeclaration>());
681 break;
682 case Statement::Kind::kDiscard:
683 SkDEBUGFAIL("Unsupported control flow");
684 break;
685 case Statement::Kind::kInlineMarker:
686 case Statement::Kind::kNop:
687 this->write(";");
688 break;
689 default:
690 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
691 break;
692 }
693 }
694
writeBlock(const Block & b)695 void PipelineStageCodeGenerator::writeBlock(const Block& b) {
696 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
697 // something here to make the code valid).
698 bool isScope = b.isScope() || b.isEmpty();
699 if (isScope) {
700 this->writeLine("{");
701 }
702 for (const std::unique_ptr<Statement>& stmt : b.children()) {
703 if (!stmt->isEmpty()) {
704 this->writeStatement(*stmt);
705 this->writeLine();
706 }
707 }
708 if (isScope) {
709 this->write("}");
710 }
711 }
712
writeDoStatement(const DoStatement & d)713 void PipelineStageCodeGenerator::writeDoStatement(const DoStatement& d) {
714 this->write("do ");
715 this->writeStatement(*d.statement());
716 this->write(" while (");
717 this->writeExpression(*d.test(), Precedence::kTopLevel);
718 this->write(");");
719 return;
720 }
721
writeForStatement(const ForStatement & f)722 void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
723 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
724 if (!f.initializer() && f.test() && !f.next()) {
725 this->write("while (");
726 this->writeExpression(*f.test(), Precedence::kTopLevel);
727 this->write(") ");
728 this->writeStatement(*f.statement());
729 return;
730 }
731
732 this->write("for (");
733 if (f.initializer() && !f.initializer()->isEmpty()) {
734 this->writeStatement(*f.initializer());
735 } else {
736 this->write("; ");
737 }
738 if (f.test()) {
739 this->writeExpression(*f.test(), Precedence::kTopLevel);
740 }
741 this->write("; ");
742 if (f.next()) {
743 this->writeExpression(*f.next(), Precedence::kTopLevel);
744 }
745 this->write(") ");
746 this->writeStatement(*f.statement());
747 }
748
generateCode()749 void PipelineStageCodeGenerator::generateCode() {
750 // Write all the program elements except for functions; prototype all the functions.
751 for (const ProgramElement* e : fProgram.elements()) {
752 this->writeProgramElementFirstPass(*e);
753 }
754
755 // We always place FunctionDefinition elements last, because the inliner likes to move function
756 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
757 // that the code relies on.
758 for (const ProgramElement* e : fProgram.elements()) {
759 this->writeProgramElementSecondPass(*e);
760 }
761 }
762
ConvertProgram(const Program & program,const char * sampleCoords,const char * inputColor,const char * destColor,Callbacks * callbacks)763 void ConvertProgram(const Program& program,
764 const char* sampleCoords,
765 const char* inputColor,
766 const char* destColor,
767 Callbacks* callbacks) {
768 PipelineStageCodeGenerator generator(program, sampleCoords, inputColor, destColor, callbacks);
769 generator.generateCode();
770 }
771
772 } // namespace PipelineStage
773 } // namespace SkSL
774
775 #endif
776