blob: 9e7bcdd1a8e4be5bd8414f98fb410ed1a0b8db65 [file] [log] [blame]
Ethan Nicholas00543112018-07-31 09:44:36 -04001/*
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
John Stiles3738ef52021-04-13 10:41:57 -04008#include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholas00543112018-07-31 09:44:36 -04009
Ethan Nicholas24c17722021-03-09 13:10:59 -050010#include "include/private/SkSLProgramElement.h"
11#include "include/private/SkSLStatement.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
Brian Osman236ddb32021-02-05 12:15:29 -050013#include "src/sksl/SkSLOperators.h"
14#include "src/sksl/SkSLStringStream.h"
15#include "src/sksl/ir/SkSLBinaryExpression.h"
Brian Osmaneb0f29d2021-08-04 11:34:16 -040016#include "src/sksl/ir/SkSLChildCall.h"
Brian Osman236ddb32021-02-05 12:15:29 -050017#include "src/sksl/ir/SkSLConstructor.h"
John Stilese3ae9682021-08-05 10:35:01 -040018#include "src/sksl/ir/SkSLConstructorArrayCast.h"
John Stilesb82e9312021-05-20 15:30:22 -040019#include "src/sksl/ir/SkSLDoStatement.h"
Brian Osman236ddb32021-02-05 12:15:29 -050020#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"
Brian Osman7da06572021-07-21 15:19:34 -040026#include "src/sksl/ir/SkSLFunctionPrototype.h"
Brian Osman236ddb32021-02-05 12:15:29 -050027#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"
Brian Osman236ddb32021-02-05 12:15:29 -050031#include "src/sksl/ir/SkSLReturnStatement.h"
Brian Osman8e756f32021-02-10 10:19:27 -050032#include "src/sksl/ir/SkSLStructDefinition.h"
John Stilesed2baba2021-09-20 19:09:13 -040033#include "src/sksl/ir/SkSLSwitchStatement.h"
Brian Osman236ddb32021-02-05 12:15:29 -050034#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"
Ethan Nicholas00543112018-07-31 09:44:36 -040038
Brian Osman690b6f32021-02-05 16:30:34 -050039#include <unordered_map>
40
Brian Osman62b039b2021-02-08 13:49:53 -050041#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -040042
Ethan Nicholas00543112018-07-31 09:44:36 -040043namespace SkSL {
Brian Osman690b6f32021-02-05 16:30:34 -050044namespace PipelineStage {
Ethan Nicholas00543112018-07-31 09:44:36 -040045
Brian Osman236ddb32021-02-05 12:15:29 -050046class PipelineStageCodeGenerator {
47public:
Brian Osman690b6f32021-02-05 16:30:34 -050048 PipelineStageCodeGenerator(const Program& program,
49 const char* sampleCoords,
Brian Osman577c6062021-04-12 17:17:19 -040050 const char* inputColor,
John Stiles50d0d092021-06-09 17:24:31 -040051 const char* destColor,
Brian Osman690b6f32021-02-05 16:30:34 -050052 Callbacks* callbacks)
53 : fProgram(program)
54 , fSampleCoords(sampleCoords)
Brian Osman577c6062021-04-12 17:17:19 -040055 , fInputColor(inputColor)
John Stiles50d0d092021-06-09 17:24:31 -040056 , fDestColor(destColor)
Brian Osman690b6f32021-02-05 16:30:34 -050057 , fCallbacks(callbacks) {}
Brian Osman236ddb32021-02-05 12:15:29 -050058
59 void generateCode();
60
61private:
John Stiles45990502021-02-16 10:55:27 -050062 using Precedence = Operator::Precedence;
Brian Osman236ddb32021-02-05 12:15:29 -050063
Ethan Nicholas962dec42021-06-10 13:06:39 -040064 void write(skstd::string_view s);
65 void writeLine(skstd::string_view s = skstd::string_view());
Brian Osman236ddb32021-02-05 12:15:29 -050066
Brian Osman55761ae2021-02-09 16:52:53 -050067 String typeName(const Type& type);
Brian Osman236ddb32021-02-05 12:15:29 -050068 void writeType(const Type& type);
69
Brian Osman7da06572021-07-21 15:19:34 -040070 String functionName(const FunctionDeclaration& decl);
Brian Osman236ddb32021-02-05 12:15:29 -050071 void writeFunction(const FunctionDefinition& f);
Brian Osman7da06572021-07-21 15:19:34 -040072 void writeFunctionPrototype(const FunctionPrototype& f);
Brian Osman236ddb32021-02-05 12:15:29 -050073
Brian Osman4f3f64c2021-03-09 16:35:41 -050074 String modifierString(const Modifiers& modifiers);
Brian Osman236ddb32021-02-05 12:15:29 -050075
Brian Osman8e756f32021-02-10 10:19:27 -050076 // Handles arrays correctly, eg: `float x[2]`
Ethan Nicholas962dec42021-06-10 13:06:39 -040077 String typedVariable(const Type& type, skstd::string_view name);
Brian Osman8e756f32021-02-10 10:19:27 -050078
Brian Osman236ddb32021-02-05 12:15:29 -050079 void writeVarDeclaration(const VarDeclaration& var);
Brian Osman690b6f32021-02-05 16:30:34 -050080 void writeGlobalVarDeclaration(const GlobalVarDeclaration& g);
Brian Osman8e756f32021-02-10 10:19:27 -050081 void writeStructDefinition(const StructDefinition& s);
Brian Osman236ddb32021-02-05 12:15:29 -050082
83 void writeExpression(const Expression& expr, Precedence parentPrecedence);
Brian Osmaneb0f29d2021-08-04 11:34:16 -040084 void writeChildCall(const ChildCall& c);
Brian Osman236ddb32021-02-05 12:15:29 -050085 void writeFunctionCall(const FunctionCall& c);
John Stilesd8eb8752021-04-01 11:49:10 -040086 void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
Brian Osman236ddb32021-02-05 12:15:29 -050087 void writeFieldAccess(const FieldAccess& f);
88 void writeSwizzle(const Swizzle& swizzle);
89 void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
90 void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
91 void writeIndexExpression(const IndexExpression& expr);
92 void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
93 void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
94 void writeVariableReference(const VariableReference& ref);
95
96 void writeStatement(const Statement& s);
97 void writeBlock(const Block& b);
98 void writeIfStatement(const IfStatement& stmt);
John Stilesb82e9312021-05-20 15:30:22 -040099 void writeDoStatement(const DoStatement& d);
Brian Osman236ddb32021-02-05 12:15:29 -0500100 void writeForStatement(const ForStatement& f);
101 void writeReturnStatement(const ReturnStatement& r);
John Stilesed2baba2021-09-20 19:09:13 -0400102 void writeSwitchStatement(const SwitchStatement& s);
Brian Osman236ddb32021-02-05 12:15:29 -0500103
104 void writeProgramElement(const ProgramElement& e);
105
106 struct AutoOutputBuffer {
107 AutoOutputBuffer(PipelineStageCodeGenerator* generator) : fGenerator(generator) {
108 fOldBuffer = fGenerator->fBuffer;
109 fGenerator->fBuffer = &fBuffer;
110 }
111
112 ~AutoOutputBuffer() {
113 fGenerator->fBuffer = fOldBuffer;
114 }
115
116 PipelineStageCodeGenerator* fGenerator;
117 StringStream* fOldBuffer;
118 StringStream fBuffer;
119 };
120
Brian Osman690b6f32021-02-05 16:30:34 -0500121 const Program& fProgram;
122 const char* fSampleCoords;
Brian Osman577c6062021-04-12 17:17:19 -0400123 const char* fInputColor;
John Stiles50d0d092021-06-09 17:24:31 -0400124 const char* fDestColor;
Brian Osman690b6f32021-02-05 16:30:34 -0500125 Callbacks* fCallbacks;
126
Brian Osman5e603c32021-02-17 15:39:06 -0500127 std::unordered_map<const Variable*, String> fVariableNames;
Brian Osman690b6f32021-02-05 16:30:34 -0500128 std::unordered_map<const FunctionDeclaration*, String> fFunctionNames;
Brian Osman8e756f32021-02-10 10:19:27 -0500129 std::unordered_map<const Type*, String> fStructNames;
Brian Osman690b6f32021-02-05 16:30:34 -0500130
131 StringStream* fBuffer = nullptr;
132 bool fCastReturnsToHalf = false;
Brian Osman236ddb32021-02-05 12:15:29 -0500133};
Ethan Nicholas00543112018-07-31 09:44:36 -0400134
Ethan Nicholas00543112018-07-31 09:44:36 -0400135
Ethan Nicholas962dec42021-06-10 13:06:39 -0400136void PipelineStageCodeGenerator::write(skstd::string_view s) {
Brian Osman236ddb32021-02-05 12:15:29 -0500137 fBuffer->write(s.data(), s.length());
Brian Osmanca21e142021-02-03 15:34:29 -0500138}
139
Ethan Nicholas962dec42021-06-10 13:06:39 -0400140void PipelineStageCodeGenerator::writeLine(skstd::string_view s) {
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400141 fBuffer->write(s.data(), s.length());
142 fBuffer->writeText("\n");
Ethan Nicholas00543112018-07-31 09:44:36 -0400143}
144
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400145void PipelineStageCodeGenerator::writeChildCall(const ChildCall& c) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400146 const ExpressionArray& arguments = c.arguments();
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400147 SkASSERT(arguments.size() >= 1);
148 int index = 0;
149 bool found = false;
150 for (const ProgramElement* p : fProgram.elements()) {
151 if (p->is<GlobalVarDeclaration>()) {
152 const GlobalVarDeclaration& global = p->as<GlobalVarDeclaration>();
153 const VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
154 if (&decl.var() == &c.child()) {
155 found = true;
156 } else if (decl.var().type().isEffectChild()) {
157 ++index;
Ethan Nicholasce008112018-08-30 09:19:50 -0400158 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400159 }
160 if (found) {
161 break;
162 }
163 }
164 SkASSERT(found);
165
166 // Shaders require a coordinate argument. Color filters require a color argument.
167 // Blenders require two color arguments.
168 String sampleOutput;
169 {
170 AutoOutputBuffer exprBuffer(this);
171 this->writeExpression(*arguments[0], Precedence::kSequence);
172
173 switch (c.child().type().typeKind()) {
174 case Type::TypeKind::kShader: {
175 SkASSERT(arguments.size() == 1);
176 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fFloat2);
177 sampleOutput = fCallbacks->sampleShader(index, exprBuffer.fBuffer.str());
Ethan Nicholasce008112018-08-30 09:19:50 -0400178 break;
179 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400180 case Type::TypeKind::kColorFilter: {
181 SkASSERT(arguments.size() == 1);
182 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fHalf4 ||
183 arguments[0]->type() == *fProgram.fContext->fTypes.fFloat4);
184 sampleOutput = fCallbacks->sampleColorFilter(index, exprBuffer.fBuffer.str());
185 break;
186 }
187 case Type::TypeKind::kBlender: {
188 SkASSERT(arguments.size() == 2);
189 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fHalf4 ||
190 arguments[0]->type() == *fProgram.fContext->fTypes.fFloat4);
191 SkASSERT(arguments[1]->type() == *fProgram.fContext->fTypes.fHalf4 ||
192 arguments[1]->type() == *fProgram.fContext->fTypes.fFloat4);
Brian Osman690b6f32021-02-05 16:30:34 -0500193
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400194 AutoOutputBuffer exprBuffer2(this);
195 this->writeExpression(*arguments[1], Precedence::kSequence);
John Stiles8050a4b2021-07-23 15:50:20 -0400196
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400197 sampleOutput = fCallbacks->sampleBlender(index, exprBuffer.fBuffer.str(),
198 exprBuffer2.fBuffer.str());
199 break;
200 }
201 default: {
202 SkDEBUGFAILF("cannot sample from type '%s'",
203 c.child().type().description().c_str());
Brian Osmanc9125aa2021-04-21 09:57:19 -0400204 }
Brian Osman690b6f32021-02-05 16:30:34 -0500205 }
Ethan Nicholasce008112018-08-30 09:19:50 -0400206 }
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400207 this->write(sampleOutput);
208 return;
209}
210
211void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
212 const FunctionDeclaration& function = c.function();
Brian Osman690b6f32021-02-05 16:30:34 -0500213
Ethan Nicholased84b732020-10-08 11:45:44 -0400214 if (function.isBuiltin()) {
Brian Osmanca21e142021-02-03 15:34:29 -0500215 this->write(function.name());
Brian Osman2e29ab52019-09-20 12:19:11 -0400216 } else {
John Stiles699736b2021-08-05 16:35:27 -0400217 this->write(this->functionName(function));
Brian Osman2e29ab52019-09-20 12:19:11 -0400218 }
Brian Osman690b6f32021-02-05 16:30:34 -0500219
220 this->write("(");
221 const char* separator = "";
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400222 for (const auto& arg : c.arguments()) {
Brian Osman690b6f32021-02-05 16:30:34 -0500223 this->write(separator);
224 separator = ", ";
225 this->writeExpression(*arg, Precedence::kSequence);
226 }
227 this->write(")");
Ethan Nicholasce008112018-08-30 09:19:50 -0400228}
229
Ethan Nicholas00543112018-07-31 09:44:36 -0400230void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
Brian Osman690b6f32021-02-05 16:30:34 -0500231 const Variable* var = ref.variable();
232 const Modifiers& modifiers = var->modifiers();
Brian Osman3c358422020-03-23 10:44:12 -0400233
Brian Osman690b6f32021-02-05 16:30:34 -0500234 if (modifiers.fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
235 this->write(fSampleCoords);
236 return;
Brian Osman577c6062021-04-12 17:17:19 -0400237 } else if (modifiers.fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN) {
238 this->write(fInputColor);
239 return;
John Stiles50d0d092021-06-09 17:24:31 -0400240 } else if (modifiers.fLayout.fBuiltin == SK_DEST_COLOR_BUILTIN) {
241 this->write(fDestColor);
242 return;
Brian Osman690b6f32021-02-05 16:30:34 -0500243 }
244
Brian Osmane49703f2021-04-19 11:15:24 -0400245 auto it = fVariableNames.find(var);
246 if (it != fVariableNames.end()) {
247 this->write(it->second);
Brian Osman690b6f32021-02-05 16:30:34 -0500248 } else {
Brian Osmane49703f2021-04-19 11:15:24 -0400249 this->write(var->name());
Ethan Nicholas00543112018-07-31 09:44:36 -0400250 }
251}
252
Brian Osmanca21e142021-02-03 15:34:29 -0500253void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& stmt) {
254 if (stmt.isStatic()) {
Ethan Nicholas00543112018-07-31 09:44:36 -0400255 this->write("@");
256 }
Brian Osmanca21e142021-02-03 15:34:29 -0500257 this->write("if (");
Brian Osman00185012021-02-04 16:07:11 -0500258 this->writeExpression(*stmt.test(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500259 this->write(") ");
260 this->writeStatement(*stmt.ifTrue());
261 if (stmt.ifFalse()) {
262 this->write(" else ");
263 this->writeStatement(*stmt.ifFalse());
264 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400265}
266
Brian Osman33316412020-11-06 10:42:51 -0500267void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
268 this->write("return");
269 if (r.expression()) {
270 this->write(" ");
271 if (fCastReturnsToHalf) {
272 this->write("half4(");
273 }
Brian Osman00185012021-02-04 16:07:11 -0500274 this->writeExpression(*r.expression(), Precedence::kTopLevel);
Brian Osman33316412020-11-06 10:42:51 -0500275 if (fCastReturnsToHalf) {
276 this->write(")");
277 }
278 }
279 this->write(";");
280}
281
John Stilesed2baba2021-09-20 19:09:13 -0400282void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
283 this->write("switch (");
284 this->writeExpression(*s.value(), Precedence::kTopLevel);
285 this->writeLine(") {");
286 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
287 const SwitchCase& c = stmt->as<SwitchCase>();
288 if (c.value()) {
289 this->write("case ");
290 this->writeExpression(*c.value(), Precedence::kTopLevel);
291 this->writeLine(":");
292 } else {
293 this->writeLine("default:");
294 }
295 if (!c.statement()->isEmpty()) {
296 this->writeStatement(*c.statement());
297 this->writeLine();
298 }
299 }
300 this->writeLine();
301 this->write("}");
302}
303
Brian Osman7da06572021-07-21 15:19:34 -0400304String PipelineStageCodeGenerator::functionName(const FunctionDeclaration& decl) {
305 if (decl.isMain()) {
306 return String(decl.name());
307 }
308
309 auto it = fFunctionNames.find(&decl);
310 if (it != fFunctionNames.end()) {
311 return it->second;
312 }
313
314 String mangledName = fCallbacks->getMangledName(String(decl.name()).c_str());
315 fFunctionNames.insert({&decl, mangledName});
316 return mangledName;
317}
318
Ethan Nicholas00543112018-07-31 09:44:36 -0400319void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
Brian Osman690b6f32021-02-05 16:30:34 -0500320 AutoOutputBuffer body(this);
Brian Osman236ddb32021-02-05 12:15:29 -0500321
Brian Osman690b6f32021-02-05 16:30:34 -0500322 // We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
323 // our code in the processor, the surrounding code is going to expect half4, so we
324 // explicitly cast any returns (from main) to half4. This is only strictly necessary
325 // if the return type is float4 - injecting it unconditionally reduces the risk of an
326 // obscure bug.
John Stilesaa4f4c72021-03-22 16:08:15 -0400327 const FunctionDeclaration& decl = f.declaration();
John Stilese8da4d22021-03-24 09:19:45 -0400328 if (decl.isMain()) {
Brian Osman690b6f32021-02-05 16:30:34 -0500329 fCastReturnsToHalf = true;
330 }
331
332 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
333 this->writeStatement(*stmt);
334 this->writeLine();
335 }
336
John Stilese8da4d22021-03-24 09:19:45 -0400337 if (decl.isMain()) {
Brian Osman690b6f32021-02-05 16:30:34 -0500338 fCastReturnsToHalf = false;
339 }
340
John Stilesaa4f4c72021-03-22 16:08:15 -0400341 // This is similar to decl.description(), but substitutes a mangled name, and handles modifiers
342 // on the function (e.g. `inline`) and its parameters (e.g. `inout`).
Brian Osman55761ae2021-02-09 16:52:53 -0500343 String declString =
John Stilesaa4f4c72021-03-22 16:08:15 -0400344 String::printf("%s%s%s %s(",
345 (decl.modifiers().fFlags & Modifiers::kInline_Flag) ? "inline " : "",
346 (decl.modifiers().fFlags & Modifiers::kNoInline_Flag) ? "noinline " : "",
347 this->typeName(decl.returnType()).c_str(),
John Stiles699736b2021-08-05 16:35:27 -0400348 this->functionName(decl).c_str());
Brian Osman55761ae2021-02-09 16:52:53 -0500349 const char* separator = "";
John Stilesaa4f4c72021-03-22 16:08:15 -0400350 for (const Variable* p : decl.parameters()) {
Brian Osman55761ae2021-02-09 16:52:53 -0500351 // TODO: Handle arrays
Brian Osman4f3f64c2021-03-09 16:35:41 -0500352 declString.appendf("%s%s%s %s",
353 separator,
354 this->modifierString(p->modifiers()).c_str(),
355 this->typeName(p->type()).c_str(),
Brian Osman55761ae2021-02-09 16:52:53 -0500356 String(p->name()).c_str());
357 separator = ", ";
358 }
359 declString.append(")");
360
John Stilese8da4d22021-03-24 09:19:45 -0400361 fCallbacks->defineFunction(declString.c_str(), body.fBuffer.str().c_str(), decl.isMain());
Brian Osman690b6f32021-02-05 16:30:34 -0500362}
363
Brian Osman7da06572021-07-21 15:19:34 -0400364void PipelineStageCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
365 const FunctionDeclaration& decl = f.declaration();
366 (void)this->functionName(decl);
367}
368
Brian Osman690b6f32021-02-05 16:30:34 -0500369void PipelineStageCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& g) {
370 const VarDeclaration& decl = g.declaration()->as<VarDeclaration>();
371 const Variable& var = decl.var();
372
Brian Osmanddcb4d92021-03-12 14:19:01 -0500373 if (var.isBuiltin() || var.type().isOpaque()) {
374 // Don't re-declare these. (eg, sk_FragCoord, or fragmentProcessor children)
Brian Osman5e603c32021-02-17 15:39:06 -0500375 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osman690b6f32021-02-05 16:30:34 -0500376 String uniformName = fCallbacks->declareUniform(&decl);
Brian Osman5e603c32021-02-17 15:39:06 -0500377 fVariableNames.insert({&var, std::move(uniformName)});
Brian Osman690b6f32021-02-05 16:30:34 -0500378 } else {
Brian Osman5e603c32021-02-17 15:39:06 -0500379 String mangledName = fCallbacks->getMangledName(String(var.name()).c_str());
Brian Osman4f3f64c2021-03-09 16:35:41 -0500380 String declaration = this->modifierString(var.modifiers()) +
Ethan Nicholas962dec42021-06-10 13:06:39 -0400381 this->typedVariable(var.type(),
382 skstd::string_view(mangledName.c_str()));
Brian Osman5e603c32021-02-17 15:39:06 -0500383 if (decl.value()) {
384 AutoOutputBuffer outputToBuffer(this);
385 this->writeExpression(*decl.value(), Precedence::kTopLevel);
386 declaration += " = ";
387 declaration += outputToBuffer.fBuffer.str();
388 }
389 declaration += ";\n";
390 fCallbacks->declareGlobal(declaration.c_str());
391 fVariableNames.insert({&var, std::move(mangledName)});
Ethan Nicholas00543112018-07-31 09:44:36 -0400392 }
393}
394
Brian Osman8e756f32021-02-10 10:19:27 -0500395void PipelineStageCodeGenerator::writeStructDefinition(const StructDefinition& s) {
396 const Type& type = s.type();
397 String mangledName = fCallbacks->getMangledName(String(type.name()).c_str());
398 String definition = "struct " + mangledName + " {\n";
399 for (const auto& f : type.fields()) {
400 definition += this->typedVariable(*f.fType, f.fName) + ";\n";
401 }
402 definition += "};\n";
403 fStructNames.insert({&type, std::move(mangledName)});
404 fCallbacks->defineStruct(definition.c_str());
405}
406
Brian Osmanca21e142021-02-03 15:34:29 -0500407void PipelineStageCodeGenerator::writeProgramElement(const ProgramElement& e) {
408 switch (e.kind()) {
409 case ProgramElement::Kind::kGlobalVar:
Brian Osman690b6f32021-02-05 16:30:34 -0500410 this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
Brian Osmanca21e142021-02-03 15:34:29 -0500411 break;
412 case ProgramElement::Kind::kFunction:
413 this->writeFunction(e.as<FunctionDefinition>());
414 break;
415 case ProgramElement::Kind::kFunctionPrototype:
Brian Osman7da06572021-07-21 15:19:34 -0400416 this->writeFunctionPrototype(e.as<FunctionPrototype>());
Brian Osmanca21e142021-02-03 15:34:29 -0500417 break;
Brian Osman8e756f32021-02-10 10:19:27 -0500418 case ProgramElement::Kind::kStructDefinition:
419 this->writeStructDefinition(e.as<StructDefinition>());
420 break;
Brian Osman690b6f32021-02-05 16:30:34 -0500421
Brian Osmanca21e142021-02-03 15:34:29 -0500422 case ProgramElement::Kind::kExtension:
423 case ProgramElement::Kind::kInterfaceBlock:
Brian Osman690b6f32021-02-05 16:30:34 -0500424 case ProgramElement::Kind::kModifiers:
Brian Osmanca21e142021-02-03 15:34:29 -0500425 default:
426 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
427 break;
Ethan Nicholas00543112018-07-31 09:44:36 -0400428 }
Brian Osmanca21e142021-02-03 15:34:29 -0500429}
430
Brian Osman55761ae2021-02-09 16:52:53 -0500431String PipelineStageCodeGenerator::typeName(const Type& type) {
John Stiles958a9392021-04-28 16:03:05 -0400432 if (type.isArray()) {
433 // This is necessary so that name mangling on arrays-of-structs works properly.
434 String arrayName = this->typeName(type.componentType());
435 arrayName.push_back('[');
Brian Osmanb42c3832021-08-27 15:19:03 -0400436 arrayName += to_string(type.columns());
John Stiles958a9392021-04-28 16:03:05 -0400437 arrayName.push_back(']');
438 return arrayName;
439 }
440
Brian Osman8e756f32021-02-10 10:19:27 -0500441 auto it = fStructNames.find(&type);
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400442 return it != fStructNames.end() ? it->second : String(type.name());
Brian Osman55761ae2021-02-09 16:52:53 -0500443}
444
Brian Osmanca21e142021-02-03 15:34:29 -0500445void PipelineStageCodeGenerator::writeType(const Type& type) {
Brian Osman55761ae2021-02-09 16:52:53 -0500446 this->write(this->typeName(type));
Brian Osmanca21e142021-02-03 15:34:29 -0500447}
448
449void PipelineStageCodeGenerator::writeExpression(const Expression& expr,
450 Precedence parentPrecedence) {
451 switch (expr.kind()) {
452 case Expression::Kind::kBinary:
453 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
454 break;
John Stiles7591d4b2021-09-13 13:32:06 -0400455 case Expression::Kind::kLiteral:
Brian Osmanca21e142021-02-03 15:34:29 -0500456 this->write(expr.description());
457 break;
Brian Osmaneb0f29d2021-08-04 11:34:16 -0400458 case Expression::Kind::kChildCall:
459 this->writeChildCall(expr.as<ChildCall>());
460 break;
John Stiles7384b372021-04-01 13:48:15 -0400461 case Expression::Kind::kConstructorArray:
John Stiles26487162021-08-10 16:03:44 -0400462 case Expression::Kind::kConstructorArrayCast:
John Stiles8cad6372021-04-07 12:31:13 -0400463 case Expression::Kind::kConstructorCompound:
464 case Expression::Kind::kConstructorCompoundCast:
John Stilese1182782021-03-30 22:09:37 -0400465 case Expression::Kind::kConstructorDiagonalMatrix:
John Stiles5abb9e12021-04-06 13:47:19 -0400466 case Expression::Kind::kConstructorMatrixResize:
John Stilesfd7252f2021-04-04 22:24:40 -0400467 case Expression::Kind::kConstructorScalarCast:
John Stiles2938eea2021-04-01 18:58:25 -0400468 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -0400469 case Expression::Kind::kConstructorStruct:
John Stiles7384b372021-04-01 13:48:15 -0400470 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
John Stilese1182782021-03-30 22:09:37 -0400471 break;
Brian Osmanca21e142021-02-03 15:34:29 -0500472 case Expression::Kind::kFieldAccess:
473 this->writeFieldAccess(expr.as<FieldAccess>());
474 break;
475 case Expression::Kind::kFunctionCall:
476 this->writeFunctionCall(expr.as<FunctionCall>());
477 break;
478 case Expression::Kind::kPrefix:
479 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
480 break;
481 case Expression::Kind::kPostfix:
482 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
483 break;
484 case Expression::Kind::kSwizzle:
485 this->writeSwizzle(expr.as<Swizzle>());
486 break;
487 case Expression::Kind::kVariableReference:
488 this->writeVariableReference(expr.as<VariableReference>());
489 break;
490 case Expression::Kind::kTernary:
491 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
492 break;
493 case Expression::Kind::kIndex:
494 this->writeIndexExpression(expr.as<IndexExpression>());
495 break;
496 case Expression::Kind::kSetting:
497 default:
498 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
499 break;
500 }
501}
502
John Stilesd8eb8752021-04-01 11:49:10 -0400503void PipelineStageCodeGenerator::writeAnyConstructor(const AnyConstructor& c,
504 Precedence parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500505 this->writeType(c.type());
506 this->write("(");
507 const char* separator = "";
John Stilesd8eb8752021-04-01 11:49:10 -0400508 for (const auto& arg : c.argumentSpan()) {
Brian Osmanca21e142021-02-03 15:34:29 -0500509 this->write(separator);
510 separator = ", ";
Brian Osman00185012021-02-04 16:07:11 -0500511 this->writeExpression(*arg, Precedence::kSequence);
Brian Osmanca21e142021-02-03 15:34:29 -0500512 }
513 this->write(")");
514}
515
516void PipelineStageCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
Brian Osman00185012021-02-04 16:07:11 -0500517 this->writeExpression(*expr.base(), Precedence::kPostfix);
Brian Osmanca21e142021-02-03 15:34:29 -0500518 this->write("[");
Brian Osman00185012021-02-04 16:07:11 -0500519 this->writeExpression(*expr.index(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500520 this->write("]");
521}
522
523void PipelineStageCodeGenerator::writeFieldAccess(const FieldAccess& f) {
524 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
Brian Osman00185012021-02-04 16:07:11 -0500525 this->writeExpression(*f.base(), Precedence::kPostfix);
Brian Osmanca21e142021-02-03 15:34:29 -0500526 this->write(".");
527 }
528 const Type& baseType = f.base()->type();
529 this->write(baseType.fields()[f.fieldIndex()].fName);
530}
531
532void PipelineStageCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
Brian Osman00185012021-02-04 16:07:11 -0500533 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
Brian Osmanca21e142021-02-03 15:34:29 -0500534 this->write(".");
535 for (int c : swizzle.components()) {
536 SkASSERT(c >= 0 && c <= 3);
537 this->write(&("x\0y\0z\0w\0"[c * 2]));
538 }
539}
540
Brian Osmanca21e142021-02-03 15:34:29 -0500541void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
542 Precedence parentPrecedence) {
543 const Expression& left = *b.left();
544 const Expression& right = *b.right();
John Stiles45990502021-02-16 10:55:27 -0500545 Operator op = b.getOperator();
Brian Osmanca21e142021-02-03 15:34:29 -0500546
John Stiles45990502021-02-16 10:55:27 -0500547 Precedence precedence = op.getBinaryPrecedence();
Brian Osmanca21e142021-02-03 15:34:29 -0500548 if (precedence >= parentPrecedence) {
549 this->write("(");
550 }
551 this->writeExpression(left, precedence);
552 this->write(" ");
John Stiles45990502021-02-16 10:55:27 -0500553 this->write(op.operatorName());
Brian Osmanca21e142021-02-03 15:34:29 -0500554 this->write(" ");
555 this->writeExpression(right, precedence);
556 if (precedence >= parentPrecedence) {
557 this->write(")");
558 }
559}
560
561void PipelineStageCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
562 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500563 if (Precedence::kTernary >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500564 this->write("(");
565 }
Brian Osman00185012021-02-04 16:07:11 -0500566 this->writeExpression(*t.test(), Precedence::kTernary);
Brian Osmanca21e142021-02-03 15:34:29 -0500567 this->write(" ? ");
Brian Osman00185012021-02-04 16:07:11 -0500568 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
Brian Osmanca21e142021-02-03 15:34:29 -0500569 this->write(" : ");
Brian Osman00185012021-02-04 16:07:11 -0500570 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
571 if (Precedence::kTernary >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500572 this->write(")");
573 }
574}
575
576void PipelineStageCodeGenerator::writePrefixExpression(const PrefixExpression& p,
577 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500578 if (Precedence::kPrefix >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500579 this->write("(");
580 }
John Stiles45990502021-02-16 10:55:27 -0500581 this->write(p.getOperator().operatorName());
Brian Osman00185012021-02-04 16:07:11 -0500582 this->writeExpression(*p.operand(), Precedence::kPrefix);
583 if (Precedence::kPrefix >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500584 this->write(")");
585 }
586}
587
588void PipelineStageCodeGenerator::writePostfixExpression(const PostfixExpression& p,
589 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500590 if (Precedence::kPostfix >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500591 this->write("(");
592 }
Brian Osman00185012021-02-04 16:07:11 -0500593 this->writeExpression(*p.operand(), Precedence::kPostfix);
John Stiles45990502021-02-16 10:55:27 -0500594 this->write(p.getOperator().operatorName());
Brian Osman00185012021-02-04 16:07:11 -0500595 if (Precedence::kPostfix >= parentPrecedence) {
Brian Osmanca21e142021-02-03 15:34:29 -0500596 this->write(")");
597 }
598}
599
Brian Osman4f3f64c2021-03-09 16:35:41 -0500600String PipelineStageCodeGenerator::modifierString(const Modifiers& modifiers) {
601 String result;
Brian Osmanca21e142021-02-03 15:34:29 -0500602 if (modifiers.fFlags & Modifiers::kConst_Flag) {
Brian Osman4f3f64c2021-03-09 16:35:41 -0500603 result.append("const ");
Brian Osmanca21e142021-02-03 15:34:29 -0500604 }
Brian Osman4f3f64c2021-03-09 16:35:41 -0500605
606 if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kOut_Flag)) {
607 result.append("inout ");
608 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
609 result.append("in ");
610 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
611 result.append("out ");
612 }
613
614 return result;
Brian Osmanca21e142021-02-03 15:34:29 -0500615}
616
Ethan Nicholas962dec42021-06-10 13:06:39 -0400617String PipelineStageCodeGenerator::typedVariable(const Type& type, skstd::string_view name) {
Brian Osman8e756f32021-02-10 10:19:27 -0500618 const Type& baseType = type.isArray() ? type.componentType() : type;
619
620 String decl = this->typeName(baseType) + " " + name;
621 if (type.isArray()) {
622 decl += "[" + to_string(type.columns()) + "]";
623 }
624 return decl;
625}
626
Brian Osmanca21e142021-02-03 15:34:29 -0500627void PipelineStageCodeGenerator::writeVarDeclaration(const VarDeclaration& var) {
Brian Osman4f3f64c2021-03-09 16:35:41 -0500628 this->write(this->modifierString(var.var().modifiers()));
Brian Osman8e756f32021-02-10 10:19:27 -0500629 this->write(this->typedVariable(var.var().type(), var.var().name()));
Brian Osmanca21e142021-02-03 15:34:29 -0500630 if (var.value()) {
631 this->write(" = ");
Brian Osman00185012021-02-04 16:07:11 -0500632 this->writeExpression(*var.value(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500633 }
634 this->write(";");
635}
636
637void PipelineStageCodeGenerator::writeStatement(const Statement& s) {
638 switch (s.kind()) {
639 case Statement::Kind::kBlock:
640 this->writeBlock(s.as<Block>());
641 break;
642 case Statement::Kind::kBreak:
643 this->write("break;");
644 break;
645 case Statement::Kind::kContinue:
646 this->write("continue;");
647 break;
648 case Statement::Kind::kExpression:
Brian Osman00185012021-02-04 16:07:11 -0500649 this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500650 this->write(";");
651 break;
John Stilesb82e9312021-05-20 15:30:22 -0400652 case Statement::Kind::kDo:
653 this->writeDoStatement(s.as<DoStatement>());
654 break;
Brian Osmanca21e142021-02-03 15:34:29 -0500655 case Statement::Kind::kFor:
656 this->writeForStatement(s.as<ForStatement>());
657 break;
658 case Statement::Kind::kIf:
659 this->writeIfStatement(s.as<IfStatement>());
660 break;
661 case Statement::Kind::kReturn:
662 this->writeReturnStatement(s.as<ReturnStatement>());
663 break;
John Stilesed2baba2021-09-20 19:09:13 -0400664 case Statement::Kind::kSwitch:
665 this->writeSwitchStatement(s.as<SwitchStatement>());
666 break;
Brian Osmanca21e142021-02-03 15:34:29 -0500667 case Statement::Kind::kVarDeclaration:
668 this->writeVarDeclaration(s.as<VarDeclaration>());
669 break;
670 case Statement::Kind::kDiscard:
Brian Osmanca21e142021-02-03 15:34:29 -0500671 SkDEBUGFAIL("Unsupported control flow");
672 break;
673 case Statement::Kind::kInlineMarker:
674 case Statement::Kind::kNop:
675 this->write(";");
676 break;
677 default:
678 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
679 break;
680 }
681}
682
683void PipelineStageCodeGenerator::writeBlock(const Block& b) {
684 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
685 // something here to make the code valid).
686 bool isScope = b.isScope() || b.isEmpty();
687 if (isScope) {
688 this->writeLine("{");
689 }
690 for (const std::unique_ptr<Statement>& stmt : b.children()) {
691 if (!stmt->isEmpty()) {
692 this->writeStatement(*stmt);
693 this->writeLine();
694 }
695 }
696 if (isScope) {
697 this->write("}");
698 }
699}
700
John Stilesb82e9312021-05-20 15:30:22 -0400701void PipelineStageCodeGenerator::writeDoStatement(const DoStatement& d) {
702 this->write("do ");
703 this->writeStatement(*d.statement());
704 this->write(" while (");
705 this->writeExpression(*d.test(), Precedence::kTopLevel);
706 this->write(");");
707 return;
708}
709
Brian Osmanca21e142021-02-03 15:34:29 -0500710void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
John Stilesb82e9312021-05-20 15:30:22 -0400711 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
712 if (!f.initializer() && f.test() && !f.next()) {
713 this->write("while (");
714 this->writeExpression(*f.test(), Precedence::kTopLevel);
715 this->write(") ");
716 this->writeStatement(*f.statement());
717 return;
718 }
719
Brian Osmanca21e142021-02-03 15:34:29 -0500720 this->write("for (");
721 if (f.initializer() && !f.initializer()->isEmpty()) {
722 this->writeStatement(*f.initializer());
723 } else {
724 this->write("; ");
725 }
726 if (f.test()) {
Brian Osman00185012021-02-04 16:07:11 -0500727 this->writeExpression(*f.test(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500728 }
729 this->write("; ");
730 if (f.next()) {
Brian Osman00185012021-02-04 16:07:11 -0500731 this->writeExpression(*f.next(), Precedence::kTopLevel);
Brian Osmanca21e142021-02-03 15:34:29 -0500732 }
733 this->write(") ");
734 this->writeStatement(*f.statement());
735}
736
Brian Osman236ddb32021-02-05 12:15:29 -0500737void PipelineStageCodeGenerator::generateCode() {
Brian Osmanca21e142021-02-03 15:34:29 -0500738 // Write all the program elements except for functions.
739 for (const ProgramElement* e : fProgram.elements()) {
740 if (!e->is<FunctionDefinition>()) {
741 this->writeProgramElement(*e);
742 }
743 }
Brian Osman236ddb32021-02-05 12:15:29 -0500744
Brian Osman690b6f32021-02-05 16:30:34 -0500745 // We always place FunctionDefinition elements last, because the inliner likes to move function
Brian Osmanca21e142021-02-03 15:34:29 -0500746 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
747 // that the code relies on.
748 for (const ProgramElement* e : fProgram.elements()) {
749 if (e->is<FunctionDefinition>()) {
750 this->writeProgramElement(*e);
751 }
752 }
Brian Osman236ddb32021-02-05 12:15:29 -0500753}
754
Brian Osman690b6f32021-02-05 16:30:34 -0500755void ConvertProgram(const Program& program,
756 const char* sampleCoords,
Brian Osman577c6062021-04-12 17:17:19 -0400757 const char* inputColor,
John Stiles50d0d092021-06-09 17:24:31 -0400758 const char* destColor,
Brian Osman690b6f32021-02-05 16:30:34 -0500759 Callbacks* callbacks) {
John Stiles50d0d092021-06-09 17:24:31 -0400760 PipelineStageCodeGenerator generator(program, sampleCoords, inputColor, destColor, callbacks);
Brian Osman236ddb32021-02-05 12:15:29 -0500761 generator.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400762}
763
Brian Osman690b6f32021-02-05 16:30:34 -0500764} // namespace PipelineStage
John Stilesa6841be2020-08-06 14:11:56 -0400765} // namespace SkSL
Brian Osmanca21e142021-02-03 15:34:29 -0500766
Brian Osman2e29ab52019-09-20 12:19:11 -0400767#endif