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