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