1 /*
2 * Copyright 2016 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/SkSLMetalCodeGenerator.h"
9
10 #include "src/sksl/SkSLCompiler.h"
11 #include "src/sksl/ir/SkSLExpressionStatement.h"
12 #include "src/sksl/ir/SkSLExtension.h"
13 #include "src/sksl/ir/SkSLIndexExpression.h"
14 #include "src/sksl/ir/SkSLModifiersDeclaration.h"
15 #include "src/sksl/ir/SkSLNop.h"
16 #include "src/sksl/ir/SkSLVariableReference.h"
17
18 #ifdef SK_MOLTENVK
19 static const uint32_t MVKMagicNum = 0x19960412;
20 #endif
21
22 namespace SkSL {
23
setupIntrinsics()24 void MetalCodeGenerator::setupIntrinsics() {
25 #define METAL(x) std::make_pair(kMetal_IntrinsicKind, k ## x ## _MetalIntrinsic)
26 #define SPECIAL(x) std::make_pair(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic)
27 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
28 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
29 fIntrinsicMap[String("equal")] = METAL(Equal);
30 fIntrinsicMap[String("notEqual")] = METAL(NotEqual);
31 fIntrinsicMap[String("lessThan")] = METAL(LessThan);
32 fIntrinsicMap[String("lessThanEqual")] = METAL(LessThanEqual);
33 fIntrinsicMap[String("greaterThan")] = METAL(GreaterThan);
34 fIntrinsicMap[String("greaterThanEqual")] = METAL(GreaterThanEqual);
35 }
36
write(const char * s)37 void MetalCodeGenerator::write(const char* s) {
38 if (!s[0]) {
39 return;
40 }
41 if (fAtLineStart) {
42 for (int i = 0; i < fIndentation; i++) {
43 fOut->writeText(" ");
44 }
45 }
46 fOut->writeText(s);
47 fAtLineStart = false;
48 }
49
writeLine(const char * s)50 void MetalCodeGenerator::writeLine(const char* s) {
51 this->write(s);
52 fOut->writeText(fLineEnding);
53 fAtLineStart = true;
54 }
55
write(const String & s)56 void MetalCodeGenerator::write(const String& s) {
57 this->write(s.c_str());
58 }
59
writeLine(const String & s)60 void MetalCodeGenerator::writeLine(const String& s) {
61 this->writeLine(s.c_str());
62 }
63
writeLine()64 void MetalCodeGenerator::writeLine() {
65 this->writeLine("");
66 }
67
writeExtension(const Extension & ext)68 void MetalCodeGenerator::writeExtension(const Extension& ext) {
69 this->writeLine("#extension " + ext.fName + " : enable");
70 }
71
writeType(const Type & type)72 void MetalCodeGenerator::writeType(const Type& type) {
73 switch (type.kind()) {
74 case Type::kStruct_Kind:
75 for (const Type* search : fWrittenStructs) {
76 if (*search == type) {
77 // already written
78 this->write(type.name());
79 return;
80 }
81 }
82 fWrittenStructs.push_back(&type);
83 this->writeLine("struct " + type.name() + " {");
84 fIndentation++;
85 this->writeFields(type.fields(), type.fOffset);
86 fIndentation--;
87 this->write("}");
88 break;
89 case Type::kVector_Kind:
90 this->writeType(type.componentType());
91 this->write(to_string(type.columns()));
92 break;
93 case Type::kMatrix_Kind:
94 this->writeType(type.componentType());
95 this->write(to_string(type.columns()));
96 this->write("x");
97 this->write(to_string(type.rows()));
98 break;
99 case Type::kSampler_Kind:
100 this->write("texture2d<float> "); // FIXME - support other texture types;
101 break;
102 default:
103 if (type == *fContext.fHalf_Type) {
104 // FIXME - Currently only supporting floats in MSL to avoid type coercion issues.
105 this->write(fContext.fFloat_Type->name());
106 } else if (type == *fContext.fByte_Type) {
107 this->write("char");
108 } else if (type == *fContext.fUByte_Type) {
109 this->write("uchar");
110 } else {
111 this->write(type.name());
112 }
113 }
114 }
115
writeExpression(const Expression & expr,Precedence parentPrecedence)116 void MetalCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
117 switch (expr.fKind) {
118 case Expression::kBinary_Kind:
119 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
120 break;
121 case Expression::kBoolLiteral_Kind:
122 this->writeBoolLiteral((BoolLiteral&) expr);
123 break;
124 case Expression::kConstructor_Kind:
125 this->writeConstructor((Constructor&) expr, parentPrecedence);
126 break;
127 case Expression::kIntLiteral_Kind:
128 this->writeIntLiteral((IntLiteral&) expr);
129 break;
130 case Expression::kFieldAccess_Kind:
131 this->writeFieldAccess(((FieldAccess&) expr));
132 break;
133 case Expression::kFloatLiteral_Kind:
134 this->writeFloatLiteral(((FloatLiteral&) expr));
135 break;
136 case Expression::kFunctionCall_Kind:
137 this->writeFunctionCall((FunctionCall&) expr);
138 break;
139 case Expression::kPrefix_Kind:
140 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
141 break;
142 case Expression::kPostfix_Kind:
143 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
144 break;
145 case Expression::kSetting_Kind:
146 this->writeSetting((Setting&) expr);
147 break;
148 case Expression::kSwizzle_Kind:
149 this->writeSwizzle((Swizzle&) expr);
150 break;
151 case Expression::kVariableReference_Kind:
152 this->writeVariableReference((VariableReference&) expr);
153 break;
154 case Expression::kTernary_Kind:
155 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
156 break;
157 case Expression::kIndex_Kind:
158 this->writeIndexExpression((IndexExpression&) expr);
159 break;
160 default:
161 ABORT("unsupported expression: %s", expr.description().c_str());
162 }
163 }
164
writeIntrinsicCall(const FunctionCall & c)165 void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
166 auto i = fIntrinsicMap.find(c.fFunction.fName);
167 SkASSERT(i != fIntrinsicMap.end());
168 Intrinsic intrinsic = i->second;
169 int32_t intrinsicId = intrinsic.second;
170 switch (intrinsic.first) {
171 case kSpecial_IntrinsicKind:
172 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId);
173 break;
174 case kMetal_IntrinsicKind:
175 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
176 switch ((MetalIntrinsic) intrinsicId) {
177 case kEqual_MetalIntrinsic:
178 this->write(" == ");
179 break;
180 case kNotEqual_MetalIntrinsic:
181 this->write(" != ");
182 break;
183 case kLessThan_MetalIntrinsic:
184 this->write(" < ");
185 break;
186 case kLessThanEqual_MetalIntrinsic:
187 this->write(" <= ");
188 break;
189 case kGreaterThan_MetalIntrinsic:
190 this->write(" > ");
191 break;
192 case kGreaterThanEqual_MetalIntrinsic:
193 this->write(" >= ");
194 break;
195 default:
196 ABORT("unsupported metal intrinsic kind");
197 }
198 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
199 break;
200 default:
201 ABORT("unsupported intrinsic kind");
202 }
203 }
204
writeFunctionCall(const FunctionCall & c)205 void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
206 const auto& entry = fIntrinsicMap.find(c.fFunction.fName);
207 if (entry != fIntrinsicMap.end()) {
208 this->writeIntrinsicCall(c);
209 return;
210 }
211 if (c.fFunction.fBuiltin && "atan" == c.fFunction.fName && 2 == c.fArguments.size()) {
212 this->write("atan2");
213 } else if (c.fFunction.fBuiltin && "inversesqrt" == c.fFunction.fName) {
214 this->write("rsqrt");
215 } else if (c.fFunction.fBuiltin && "inverse" == c.fFunction.fName) {
216 SkASSERT(c.fArguments.size() == 1);
217 this->writeInverseHack(*c.fArguments[0]);
218 } else if (c.fFunction.fBuiltin && "dFdx" == c.fFunction.fName) {
219 this->write("dfdx");
220 } else if (c.fFunction.fBuiltin && "dFdy" == c.fFunction.fName) {
221 // Flipping Y also negates the Y derivatives.
222 this->write((fProgram.fSettings.fFlipY) ? "-dfdy" : "dfdy");
223 } else {
224 this->writeName(c.fFunction.fName);
225 }
226 this->write("(");
227 const char* separator = "";
228 if (this->requirements(c.fFunction) & kInputs_Requirement) {
229 this->write("_in");
230 separator = ", ";
231 }
232 if (this->requirements(c.fFunction) & kOutputs_Requirement) {
233 this->write(separator);
234 this->write("_out");
235 separator = ", ";
236 }
237 if (this->requirements(c.fFunction) & kUniforms_Requirement) {
238 this->write(separator);
239 this->write("_uniforms");
240 separator = ", ";
241 }
242 if (this->requirements(c.fFunction) & kGlobals_Requirement) {
243 this->write(separator);
244 this->write("_globals");
245 separator = ", ";
246 }
247 if (this->requirements(c.fFunction) & kFragCoord_Requirement) {
248 this->write(separator);
249 this->write("_fragCoord");
250 separator = ", ";
251 }
252 for (size_t i = 0; i < c.fArguments.size(); ++i) {
253 const Expression& arg = *c.fArguments[i];
254 this->write(separator);
255 separator = ", ";
256 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
257 this->write("&");
258 }
259 this->writeExpression(arg, kSequence_Precedence);
260 }
261 this->write(")");
262 }
263
writeInverseHack(const Expression & mat)264 void MetalCodeGenerator::writeInverseHack(const Expression& mat) {
265 String typeName = mat.fType.name();
266 String name = typeName + "_inverse";
267 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
268 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
269 fWrittenIntrinsics.insert(name);
270 fExtraFunctions.writeText((
271 typeName + " " + name + "(" + typeName + " m) {"
272 " return float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]) * (1/determinant(m));"
273 "}"
274 ).c_str());
275 }
276 }
277 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
278 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
279 fWrittenIntrinsics.insert(name);
280 fExtraFunctions.writeText((
281 typeName + " " + name + "(" + typeName + " m) {"
282 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
283 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
284 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
285 " float b01 = a22 * a11 - a12 * a21;"
286 " float b11 = -a22 * a10 + a12 * a20;"
287 " float b21 = a21 * a10 - a11 * a20;"
288 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
289 " return " + typeName +
290 " (b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
291 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
292 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) * "
293 " (1/det);"
294 "}"
295 ).c_str());
296 }
297 }
298 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
299 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
300 fWrittenIntrinsics.insert(name);
301 fExtraFunctions.writeText((
302 typeName + " " + name + "(" + typeName + " m) {"
303 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
304 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
305 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
306 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
307 " float b00 = a00 * a11 - a01 * a10;"
308 " float b01 = a00 * a12 - a02 * a10;"
309 " float b02 = a00 * a13 - a03 * a10;"
310 " float b03 = a01 * a12 - a02 * a11;"
311 " float b04 = a01 * a13 - a03 * a11;"
312 " float b05 = a02 * a13 - a03 * a12;"
313 " float b06 = a20 * a31 - a21 * a30;"
314 " float b07 = a20 * a32 - a22 * a30;"
315 " float b08 = a20 * a33 - a23 * a30;"
316 " float b09 = a21 * a32 - a22 * a31;"
317 " float b10 = a21 * a33 - a23 * a31;"
318 " float b11 = a22 * a33 - a23 * a32;"
319 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
320 " b04 * b07 + b05 * b06;"
321 " return " + typeName + "(a11 * b11 - a12 * b10 + a13 * b09,"
322 " a02 * b10 - a01 * b11 - a03 * b09,"
323 " a31 * b05 - a32 * b04 + a33 * b03,"
324 " a22 * b04 - a21 * b05 - a23 * b03,"
325 " a12 * b08 - a10 * b11 - a13 * b07,"
326 " a00 * b11 - a02 * b08 + a03 * b07,"
327 " a32 * b02 - a30 * b05 - a33 * b01,"
328 " a20 * b05 - a22 * b02 + a23 * b01,"
329 " a10 * b10 - a11 * b08 + a13 * b06,"
330 " a01 * b08 - a00 * b10 - a03 * b06,"
331 " a30 * b04 - a31 * b02 + a33 * b00,"
332 " a21 * b02 - a20 * b04 - a23 * b00,"
333 " a11 * b07 - a10 * b09 - a12 * b06,"
334 " a00 * b09 - a01 * b07 + a02 * b06,"
335 " a31 * b01 - a30 * b03 - a32 * b00,"
336 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
337 "}"
338 ).c_str());
339 }
340 }
341 this->write(name);
342 }
343
writeSpecialIntrinsic(const FunctionCall & c,SpecialIntrinsic kind)344 void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) {
345 switch (kind) {
346 case kTexture_SpecialIntrinsic:
347 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
348 this->write(".sample(");
349 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
350 this->write(SAMPLER_SUFFIX);
351 this->write(", ");
352 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
353 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
354 this->write(".xy)"); // FIXME - add projection functionality
355 } else {
356 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
357 this->write(")");
358 }
359 break;
360 case kMod_SpecialIntrinsic:
361 // fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y)
362 this->write("((");
363 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
364 this->write(") - (");
365 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
366 this->write(") * floor((");
367 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
368 this->write(") / (");
369 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
370 this->write(")))");
371 break;
372 default:
373 ABORT("unsupported special intrinsic kind");
374 }
375 }
376
377 // If it hasn't already been written, writes a constructor for 'matrix' which takes a single value
378 // of type 'arg'.
getMatrixConstructHelper(const Type & matrix,const Type & arg)379 String MetalCodeGenerator::getMatrixConstructHelper(const Type& matrix, const Type& arg) {
380 String key = matrix.name() + arg.name();
381 auto found = fHelpers.find(key);
382 if (found != fHelpers.end()) {
383 return found->second;
384 }
385 String name;
386 int columns = matrix.columns();
387 int rows = matrix.rows();
388 if (arg.isNumber()) {
389 // creating a matrix from a single scalar value
390 name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float";
391 fExtraFunctions.printf("float%dx%d %s(float x) {\n",
392 columns, rows, name.c_str());
393 fExtraFunctions.printf(" return float%dx%d(", columns, rows);
394 for (int i = 0; i < columns; ++i) {
395 if (i > 0) {
396 fExtraFunctions.writeText(", ");
397 }
398 fExtraFunctions.printf("float%d(", rows);
399 for (int j = 0; j < rows; ++j) {
400 if (j > 0) {
401 fExtraFunctions.writeText(", ");
402 }
403 if (i == j) {
404 fExtraFunctions.writeText("x");
405 } else {
406 fExtraFunctions.writeText("0");
407 }
408 }
409 fExtraFunctions.writeText(")");
410 }
411 fExtraFunctions.writeText(");\n}\n");
412 } else if (arg.kind() == Type::kMatrix_Kind) {
413 // creating a matrix from another matrix
414 int argColumns = arg.columns();
415 int argRows = arg.rows();
416 name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float" +
417 to_string(argColumns) + "x" + to_string(argRows);
418 fExtraFunctions.printf("float%dx%d %s(float%dx%d m) {\n",
419 columns, rows, name.c_str(), argColumns, argRows);
420 fExtraFunctions.printf(" return float%dx%d(", columns, rows);
421 for (int i = 0; i < columns; ++i) {
422 if (i > 0) {
423 fExtraFunctions.writeText(", ");
424 }
425 fExtraFunctions.printf("float%d(", rows);
426 for (int j = 0; j < rows; ++j) {
427 if (j > 0) {
428 fExtraFunctions.writeText(", ");
429 }
430 if (i < argColumns && j < argRows) {
431 fExtraFunctions.printf("m[%d][%d]", i, j);
432 } else {
433 fExtraFunctions.writeText("0");
434 }
435 }
436 fExtraFunctions.writeText(")");
437 }
438 fExtraFunctions.writeText(");\n}\n");
439 } else if (matrix.rows() == 2 && matrix.columns() == 2 && arg == *fContext.fFloat4_Type) {
440 // float2x2(float4) doesn't work, need to split it into float2x2(float2, float2)
441 name = "float2x2_from_float4";
442 fExtraFunctions.printf(
443 "float2x2 %s(float4 v) {\n"
444 " return float2x2(float2(v[0], v[1]), float2(v[2], v[3]));\n"
445 "}\n",
446 name.c_str()
447 );
448 } else {
449 SkASSERT(false);
450 name = "<error>";
451 }
452 fHelpers[key] = name;
453 return name;
454 }
455
canCoerce(const Type & t1,const Type & t2)456 bool MetalCodeGenerator::canCoerce(const Type& t1, const Type& t2) {
457 if (t1.columns() != t2.columns() || t1.rows() != t2.rows()) {
458 return false;
459 }
460 if (t1.columns() > 1) {
461 return this->canCoerce(t1.componentType(), t2.componentType());
462 }
463 return t1.isFloat() && t2.isFloat();
464 }
465
writeConstructor(const Constructor & c,Precedence parentPrecedence)466 void MetalCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
467 if (c.fArguments.size() == 1 && this->canCoerce(c.fType, c.fArguments[0]->fType)) {
468 this->writeExpression(*c.fArguments[0], parentPrecedence);
469 return;
470 }
471 if (c.fType.kind() == Type::kMatrix_Kind && c.fArguments.size() == 1) {
472 const Expression& arg = *c.fArguments[0];
473 String name = this->getMatrixConstructHelper(c.fType, arg.fType);
474 this->write(name);
475 this->write("(");
476 this->writeExpression(arg, kSequence_Precedence);
477 this->write(")");
478 } else {
479 this->writeType(c.fType);
480 this->write("(");
481 const char* separator = "";
482 int scalarCount = 0;
483 for (const auto& arg : c.fArguments) {
484 this->write(separator);
485 separator = ", ";
486 if (Type::kMatrix_Kind == c.fType.kind() && arg->fType.columns() != c.fType.rows()) {
487 // merge scalars and smaller vectors together
488 if (!scalarCount) {
489 this->writeType(c.fType.componentType());
490 this->write(to_string(c.fType.rows()));
491 this->write("(");
492 }
493 scalarCount += arg->fType.columns();
494 }
495 this->writeExpression(*arg, kSequence_Precedence);
496 if (scalarCount && scalarCount == c.fType.rows()) {
497 this->write(")");
498 scalarCount = 0;
499 }
500 }
501 this->write(")");
502 }
503 }
504
writeFragCoord()505 void MetalCodeGenerator::writeFragCoord() {
506 if (fRTHeightName.length()) {
507 this->write("float4(_fragCoord.x, ");
508 this->write(fRTHeightName.c_str());
509 this->write(" - _fragCoord.y, 0.0, _fragCoord.w)");
510 } else {
511 this->write("float4(_fragCoord.x, _fragCoord.y, 0.0, _fragCoord.w)");
512 }
513 }
514
writeVariableReference(const VariableReference & ref)515 void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
516 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
517 case SK_FRAGCOLOR_BUILTIN:
518 this->write("_out->sk_FragColor");
519 break;
520 case SK_FRAGCOORD_BUILTIN:
521 this->writeFragCoord();
522 break;
523 case SK_VERTEXID_BUILTIN:
524 this->write("sk_VertexID");
525 break;
526 case SK_INSTANCEID_BUILTIN:
527 this->write("sk_InstanceID");
528 break;
529 case SK_CLOCKWISE_BUILTIN:
530 // We'd set the front facing winding in the MTLRenderCommandEncoder to be counter
531 // clockwise to match Skia convention. This is also the default in MoltenVK.
532 this->write(fProgram.fSettings.fFlipY ? "_frontFacing" : "(!_frontFacing)");
533 break;
534 default:
535 if (Variable::kGlobal_Storage == ref.fVariable.fStorage) {
536 if (ref.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
537 this->write("_in.");
538 } else if (ref.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
539 this->write("_out->");
540 } else if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
541 ref.fVariable.fType.kind() != Type::kSampler_Kind) {
542 this->write("_uniforms.");
543 } else {
544 this->write("_globals->");
545 }
546 }
547 this->writeName(ref.fVariable.fName);
548 }
549 }
550
writeIndexExpression(const IndexExpression & expr)551 void MetalCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
552 this->writeExpression(*expr.fBase, kPostfix_Precedence);
553 this->write("[");
554 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
555 this->write("]");
556 }
557
writeFieldAccess(const FieldAccess & f)558 void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
559 const Type::Field* field = &f.fBase->fType.fields()[f.fFieldIndex];
560 if (FieldAccess::kDefault_OwnerKind == f.fOwnerKind) {
561 this->writeExpression(*f.fBase, kPostfix_Precedence);
562 this->write(".");
563 }
564 switch (field->fModifiers.fLayout.fBuiltin) {
565 case SK_CLIPDISTANCE_BUILTIN:
566 this->write("gl_ClipDistance");
567 break;
568 case SK_POSITION_BUILTIN:
569 this->write("_out->sk_Position");
570 break;
571 default:
572 if (field->fName == "sk_PointSize") {
573 this->write("_out->sk_PointSize");
574 } else {
575 if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) {
576 this->write("_globals->");
577 this->write(fInterfaceBlockNameMap[fInterfaceBlockMap[field]]);
578 this->write("->");
579 }
580 this->writeName(field->fName);
581 }
582 }
583 }
584
writeSwizzle(const Swizzle & swizzle)585 void MetalCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
586 int last = swizzle.fComponents.back();
587 if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
588 this->writeType(swizzle.fType);
589 this->write("(");
590 }
591 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
592 this->write(".");
593 for (int c : swizzle.fComponents) {
594 if (c >= 0) {
595 this->write(&("x\0y\0z\0w\0"[c * 2]));
596 }
597 }
598 if (last == SKSL_SWIZZLE_0) {
599 this->write(", 0)");
600 }
601 else if (last == SKSL_SWIZZLE_1) {
602 this->write(", 1)");
603 }
604 }
605
GetBinaryPrecedence(Token::Kind op)606 MetalCodeGenerator::Precedence MetalCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
607 switch (op) {
608 case Token::STAR: // fall through
609 case Token::SLASH: // fall through
610 case Token::PERCENT: return MetalCodeGenerator::kMultiplicative_Precedence;
611 case Token::PLUS: // fall through
612 case Token::MINUS: return MetalCodeGenerator::kAdditive_Precedence;
613 case Token::SHL: // fall through
614 case Token::SHR: return MetalCodeGenerator::kShift_Precedence;
615 case Token::LT: // fall through
616 case Token::GT: // fall through
617 case Token::LTEQ: // fall through
618 case Token::GTEQ: return MetalCodeGenerator::kRelational_Precedence;
619 case Token::EQEQ: // fall through
620 case Token::NEQ: return MetalCodeGenerator::kEquality_Precedence;
621 case Token::BITWISEAND: return MetalCodeGenerator::kBitwiseAnd_Precedence;
622 case Token::BITWISEXOR: return MetalCodeGenerator::kBitwiseXor_Precedence;
623 case Token::BITWISEOR: return MetalCodeGenerator::kBitwiseOr_Precedence;
624 case Token::LOGICALAND: return MetalCodeGenerator::kLogicalAnd_Precedence;
625 case Token::LOGICALXOR: return MetalCodeGenerator::kLogicalXor_Precedence;
626 case Token::LOGICALOR: return MetalCodeGenerator::kLogicalOr_Precedence;
627 case Token::EQ: // fall through
628 case Token::PLUSEQ: // fall through
629 case Token::MINUSEQ: // fall through
630 case Token::STAREQ: // fall through
631 case Token::SLASHEQ: // fall through
632 case Token::PERCENTEQ: // fall through
633 case Token::SHLEQ: // fall through
634 case Token::SHREQ: // fall through
635 case Token::LOGICALANDEQ: // fall through
636 case Token::LOGICALXOREQ: // fall through
637 case Token::LOGICALOREQ: // fall through
638 case Token::BITWISEANDEQ: // fall through
639 case Token::BITWISEXOREQ: // fall through
640 case Token::BITWISEOREQ: return MetalCodeGenerator::kAssignment_Precedence;
641 case Token::COMMA: return MetalCodeGenerator::kSequence_Precedence;
642 default: ABORT("unsupported binary operator");
643 }
644 }
645
writeMatrixTimesEqualHelper(const Type & left,const Type & right,const Type & result)646 void MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Type& right,
647 const Type& result) {
648 String key = "TimesEqual" + left.name() + right.name();
649 if (fHelpers.find(key) == fHelpers.end()) {
650 fExtraFunctions.printf("%s operator*=(thread %s& left, thread const %s& right) {\n"
651 " left = left * right;\n"
652 " return left;\n"
653 "}", result.name().c_str(), left.name().c_str(),
654 right.name().c_str());
655 }
656 }
657
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)658 void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
659 Precedence parentPrecedence) {
660 Precedence precedence = GetBinaryPrecedence(b.fOperator);
661 bool needParens = precedence >= parentPrecedence;
662 switch (b.fOperator) {
663 case Token::EQEQ:
664 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
665 this->write("all");
666 needParens = true;
667 }
668 break;
669 case Token::NEQ:
670 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
671 this->write("any");
672 needParens = true;
673 }
674 break;
675 default:
676 break;
677 }
678 if (needParens) {
679 this->write("(");
680 }
681 if (Compiler::IsAssignment(b.fOperator) &&
682 Expression::kVariableReference_Kind == b.fLeft->fKind &&
683 Variable::kParameter_Storage == ((VariableReference&) *b.fLeft).fVariable.fStorage &&
684 (((VariableReference&) *b.fLeft).fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
685 // writing to an out parameter. Since we have to turn those into pointers, we have to
686 // dereference it here.
687 this->write("*");
688 }
689 if (b.fOperator == Token::STAREQ && b.fLeft->fType.kind() == Type::kMatrix_Kind &&
690 b.fRight->fType.kind() == Type::kMatrix_Kind) {
691 this->writeMatrixTimesEqualHelper(b.fLeft->fType, b.fRight->fType, b.fType);
692 }
693 this->writeExpression(*b.fLeft, precedence);
694 if (b.fOperator != Token::EQ && Compiler::IsAssignment(b.fOperator) &&
695 Expression::kSwizzle_Kind == b.fLeft->fKind && !b.fLeft->hasSideEffects()) {
696 // This doesn't compile in Metal:
697 // float4 x = float4(1);
698 // x.xy *= float2x2(...);
699 // with the error message "non-const reference cannot bind to vector element",
700 // but switching it to x.xy = x.xy * float2x2(...) fixes it. We perform this tranformation
701 // as long as the LHS has no side effects, and hope for the best otherwise.
702 this->write(" = ");
703 this->writeExpression(*b.fLeft, kAssignment_Precedence);
704 this->write(" ");
705 String op = Compiler::OperatorName(b.fOperator);
706 SkASSERT(op.endsWith("="));
707 this->write(op.substr(0, op.size() - 1).c_str());
708 this->write(" ");
709 } else {
710 this->write(String(" ") + Compiler::OperatorName(b.fOperator) + " ");
711 }
712 this->writeExpression(*b.fRight, precedence);
713 if (needParens) {
714 this->write(")");
715 }
716 }
717
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)718 void MetalCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
719 Precedence parentPrecedence) {
720 if (kTernary_Precedence >= parentPrecedence) {
721 this->write("(");
722 }
723 this->writeExpression(*t.fTest, kTernary_Precedence);
724 this->write(" ? ");
725 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
726 this->write(" : ");
727 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
728 if (kTernary_Precedence >= parentPrecedence) {
729 this->write(")");
730 }
731 }
732
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)733 void MetalCodeGenerator::writePrefixExpression(const PrefixExpression& p,
734 Precedence parentPrecedence) {
735 if (kPrefix_Precedence >= parentPrecedence) {
736 this->write("(");
737 }
738 this->write(Compiler::OperatorName(p.fOperator));
739 this->writeExpression(*p.fOperand, kPrefix_Precedence);
740 if (kPrefix_Precedence >= parentPrecedence) {
741 this->write(")");
742 }
743 }
744
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)745 void MetalCodeGenerator::writePostfixExpression(const PostfixExpression& p,
746 Precedence parentPrecedence) {
747 if (kPostfix_Precedence >= parentPrecedence) {
748 this->write("(");
749 }
750 this->writeExpression(*p.fOperand, kPostfix_Precedence);
751 this->write(Compiler::OperatorName(p.fOperator));
752 if (kPostfix_Precedence >= parentPrecedence) {
753 this->write(")");
754 }
755 }
756
writeBoolLiteral(const BoolLiteral & b)757 void MetalCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
758 this->write(b.fValue ? "true" : "false");
759 }
760
writeIntLiteral(const IntLiteral & i)761 void MetalCodeGenerator::writeIntLiteral(const IntLiteral& i) {
762 if (i.fType == *fContext.fUInt_Type) {
763 this->write(to_string(i.fValue & 0xffffffff) + "u");
764 } else {
765 this->write(to_string((int32_t) i.fValue));
766 }
767 }
768
writeFloatLiteral(const FloatLiteral & f)769 void MetalCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
770 this->write(to_string(f.fValue));
771 }
772
writeSetting(const Setting & s)773 void MetalCodeGenerator::writeSetting(const Setting& s) {
774 ABORT("internal error; setting was not folded to a constant during compilation\n");
775 }
776
writeFunction(const FunctionDefinition & f)777 void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
778 fRTHeightName = fProgram.fInputs.fRTHeight ? "_globals->_anonInterface0->u_skRTHeight" : "";
779 const char* separator = "";
780 if ("main" == f.fDeclaration.fName) {
781 switch (fProgram.fKind) {
782 case Program::kFragment_Kind:
783 #ifdef SK_MOLTENVK
784 this->write("fragment Outputs main0");
785 #else
786 this->write("fragment Outputs fragmentMain");
787 #endif
788 break;
789 case Program::kVertex_Kind:
790 #ifdef SK_MOLTENVK
791 this->write("vertex Outputs main0");
792 #else
793 this->write("vertex Outputs vertexMain");
794 #endif
795 break;
796 default:
797 SkASSERT(false);
798 }
799 this->write("(Inputs _in [[stage_in]]");
800 if (-1 != fUniformBuffer) {
801 this->write(", constant Uniforms& _uniforms [[buffer(" +
802 to_string(fUniformBuffer) + ")]]");
803 }
804 for (const auto& e : fProgram) {
805 if (ProgramElement::kVar_Kind == e.fKind) {
806 VarDeclarations& decls = (VarDeclarations&) e;
807 if (!decls.fVars.size()) {
808 continue;
809 }
810 for (const auto& stmt: decls.fVars) {
811 VarDeclaration& var = (VarDeclaration&) *stmt;
812 if (var.fVar->fType.kind() == Type::kSampler_Kind) {
813 this->write(", texture2d<float> "); // FIXME - support other texture types
814 this->writeName(var.fVar->fName);
815 this->write("[[texture(");
816 this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
817 this->write(")]]");
818 this->write(", sampler ");
819 this->writeName(var.fVar->fName);
820 this->write(SAMPLER_SUFFIX);
821 this->write("[[sampler(");
822 this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
823 this->write(")]]");
824 }
825 }
826 } else if (ProgramElement::kInterfaceBlock_Kind == e.fKind) {
827 InterfaceBlock& intf = (InterfaceBlock&) e;
828 if ("sk_PerVertex" == intf.fTypeName) {
829 continue;
830 }
831 this->write(", constant ");
832 this->writeType(intf.fVariable.fType);
833 this->write("& " );
834 this->write(fInterfaceBlockNameMap[&intf]);
835 this->write(" [[buffer(");
836 #ifdef SK_MOLTENVK
837 this->write(to_string(intf.fVariable.fModifiers.fLayout.fSet));
838 #else
839 this->write(to_string(intf.fVariable.fModifiers.fLayout.fBinding));
840 #endif
841 this->write(")]]");
842 }
843 }
844 if (fProgram.fKind == Program::kFragment_Kind) {
845 if (fProgram.fInputs.fRTHeight && fInterfaceBlockNameMap.empty()) {
846 #ifdef SK_MOLTENVK
847 this->write(", constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(0)]]");
848 #else
849 this->write(", constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(1)]]");
850 #endif
851 fRTHeightName = "_anonInterface0.u_skRTHeight";
852 }
853 this->write(", bool _frontFacing [[front_facing]]");
854 this->write(", float4 _fragCoord [[position]]");
855 } else if (fProgram.fKind == Program::kVertex_Kind) {
856 this->write(", uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
857 }
858 separator = ", ";
859 } else {
860 this->writeType(f.fDeclaration.fReturnType);
861 this->write(" ");
862 this->writeName(f.fDeclaration.fName);
863 this->write("(");
864 Requirements requirements = this->requirements(f.fDeclaration);
865 if (requirements & kInputs_Requirement) {
866 this->write("Inputs _in");
867 separator = ", ";
868 }
869 if (requirements & kOutputs_Requirement) {
870 this->write(separator);
871 this->write("thread Outputs* _out");
872 separator = ", ";
873 }
874 if (requirements & kUniforms_Requirement) {
875 this->write(separator);
876 this->write("Uniforms _uniforms");
877 separator = ", ";
878 }
879 if (requirements & kGlobals_Requirement) {
880 this->write(separator);
881 this->write("thread Globals* _globals");
882 separator = ", ";
883 }
884 if (requirements & kFragCoord_Requirement) {
885 this->write(separator);
886 this->write("float4 _fragCoord");
887 separator = ", ";
888 }
889 }
890 for (const auto& param : f.fDeclaration.fParameters) {
891 this->write(separator);
892 separator = ", ";
893 this->writeModifiers(param->fModifiers, false);
894 std::vector<int> sizes;
895 const Type* type = ¶m->fType;
896 while (Type::kArray_Kind == type->kind()) {
897 sizes.push_back(type->columns());
898 type = &type->componentType();
899 }
900 this->writeType(*type);
901 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
902 this->write("*");
903 }
904 this->write(" ");
905 this->writeName(param->fName);
906 for (int s : sizes) {
907 if (s <= 0) {
908 this->write("[]");
909 } else {
910 this->write("[" + to_string(s) + "]");
911 }
912 }
913 }
914 this->writeLine(") {");
915
916 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
917
918 if ("main" == f.fDeclaration.fName) {
919 if (fNeedsGlobalStructInit) {
920 this->writeLine(" Globals globalStruct;");
921 this->writeLine(" thread Globals* _globals = &globalStruct;");
922 for (const auto& intf: fInterfaceBlockNameMap) {
923 const auto& intfName = intf.second;
924 this->write(" _globals->");
925 this->writeName(intfName);
926 this->write(" = &");
927 this->writeName(intfName);
928 this->write(";\n");
929 }
930 for (const auto& var: fInitNonConstGlobalVars) {
931 this->write(" _globals->");
932 this->writeName(var->fVar->fName);
933 this->write(" = ");
934 this->writeVarInitializer(*var->fVar, *var->fValue);
935 this->writeLine(";");
936 }
937 for (const auto& texture: fTextures) {
938 this->write(" _globals->");
939 this->writeName(texture->fName);
940 this->write(" = ");
941 this->writeName(texture->fName);
942 this->write(";\n");
943 this->write(" _globals->");
944 this->writeName(texture->fName);
945 this->write(SAMPLER_SUFFIX);
946 this->write(" = ");
947 this->writeName(texture->fName);
948 this->write(SAMPLER_SUFFIX);
949 this->write(";\n");
950 }
951 }
952 this->writeLine(" Outputs _outputStruct;");
953 this->writeLine(" thread Outputs* _out = &_outputStruct;");
954 }
955 fFunctionHeader = "";
956 OutputStream* oldOut = fOut;
957 StringStream buffer;
958 fOut = &buffer;
959 fIndentation++;
960 this->writeStatements(((Block&) *f.fBody).fStatements);
961 if ("main" == f.fDeclaration.fName) {
962 switch (fProgram.fKind) {
963 case Program::kFragment_Kind:
964 this->writeLine("return *_out;");
965 break;
966 case Program::kVertex_Kind:
967 this->writeLine("_out->sk_Position.y = -_out->sk_Position.y;");
968 this->writeLine("return *_out;"); // FIXME - detect if function already has return
969 break;
970 default:
971 SkASSERT(false);
972 }
973 }
974 fIndentation--;
975 this->writeLine("}");
976
977 fOut = oldOut;
978 this->write(fFunctionHeader);
979 this->write(buffer.str());
980 }
981
writeModifiers(const Modifiers & modifiers,bool globalContext)982 void MetalCodeGenerator::writeModifiers(const Modifiers& modifiers,
983 bool globalContext) {
984 if (modifiers.fFlags & Modifiers::kOut_Flag) {
985 this->write("thread ");
986 }
987 if (modifiers.fFlags & Modifiers::kConst_Flag) {
988 this->write("constant ");
989 }
990 }
991
writeInterfaceBlock(const InterfaceBlock & intf)992 void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
993 if ("sk_PerVertex" == intf.fTypeName) {
994 return;
995 }
996 this->writeModifiers(intf.fVariable.fModifiers, true);
997 this->write("struct ");
998 this->writeLine(intf.fTypeName + " {");
999 const Type* structType = &intf.fVariable.fType;
1000 fWrittenStructs.push_back(structType);
1001 while (Type::kArray_Kind == structType->kind()) {
1002 structType = &structType->componentType();
1003 }
1004 fIndentation++;
1005 writeFields(structType->fields(), structType->fOffset, &intf);
1006 if (fProgram.fInputs.fRTHeight) {
1007 this->writeLine("float u_skRTHeight;");
1008 }
1009 fIndentation--;
1010 this->write("}");
1011 if (intf.fInstanceName.size()) {
1012 this->write(" ");
1013 this->write(intf.fInstanceName);
1014 for (const auto& size : intf.fSizes) {
1015 this->write("[");
1016 if (size) {
1017 this->writeExpression(*size, kTopLevel_Precedence);
1018 }
1019 this->write("]");
1020 }
1021 fInterfaceBlockNameMap[&intf] = intf.fInstanceName;
1022 } else {
1023 fInterfaceBlockNameMap[&intf] = "_anonInterface" + to_string(fAnonInterfaceCount++);
1024 }
1025 this->writeLine(";");
1026 }
1027
writeFields(const std::vector<Type::Field> & fields,int parentOffset,const InterfaceBlock * parentIntf)1028 void MetalCodeGenerator::writeFields(const std::vector<Type::Field>& fields, int parentOffset,
1029 const InterfaceBlock* parentIntf) {
1030 #ifdef SK_MOLTENVK
1031 MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
1032 #else
1033 MemoryLayout memoryLayout(MemoryLayout::kMetal_Standard);
1034 #endif
1035 int currentOffset = 0;
1036 for (const auto& field: fields) {
1037 int fieldOffset = field.fModifiers.fLayout.fOffset;
1038 const Type* fieldType = field.fType;
1039 if (fieldOffset != -1) {
1040 if (currentOffset > fieldOffset) {
1041 fErrors.error(parentOffset,
1042 "offset of field '" + field.fName + "' must be at least " +
1043 to_string((int) currentOffset));
1044 } else if (currentOffset < fieldOffset) {
1045 this->write("char pad");
1046 this->write(to_string(fPaddingCount++));
1047 this->write("[");
1048 this->write(to_string(fieldOffset - currentOffset));
1049 this->writeLine("];");
1050 currentOffset = fieldOffset;
1051 }
1052 int alignment = memoryLayout.alignment(*fieldType);
1053 if (fieldOffset % alignment) {
1054 fErrors.error(parentOffset,
1055 "offset of field '" + field.fName + "' must be a multiple of " +
1056 to_string((int) alignment));
1057 }
1058 }
1059 #ifdef SK_MOLTENVK
1060 if (fieldType->kind() == Type::kVector_Kind &&
1061 fieldType->columns() == 3) {
1062 SkASSERT(memoryLayout.size(*fieldType) == 3);
1063 // Pack all vec3 types so that their size in bytes will match what was expected in the
1064 // original SkSL code since MSL has vec3 sizes equal to 4 * component type, while SkSL
1065 // has vec3 equal to 3 * component type.
1066
1067 // FIXME - Packed vectors can't be accessed by swizzles, but can be indexed into. A
1068 // combination of this being a problem which only occurs when using MoltenVK and the
1069 // fact that we haven't swizzled a vec3 yet means that this problem hasn't been
1070 // addressed.
1071 this->write(PACKED_PREFIX);
1072 }
1073 #endif
1074 currentOffset += memoryLayout.size(*fieldType);
1075 std::vector<int> sizes;
1076 while (fieldType->kind() == Type::kArray_Kind) {
1077 sizes.push_back(fieldType->columns());
1078 fieldType = &fieldType->componentType();
1079 }
1080 this->writeModifiers(field.fModifiers, false);
1081 this->writeType(*fieldType);
1082 this->write(" ");
1083 this->writeName(field.fName);
1084 for (int s : sizes) {
1085 if (s <= 0) {
1086 this->write("[]");
1087 } else {
1088 this->write("[" + to_string(s) + "]");
1089 }
1090 }
1091 this->writeLine(";");
1092 if (parentIntf) {
1093 fInterfaceBlockMap[&field] = parentIntf;
1094 }
1095 }
1096 }
1097
writeVarInitializer(const Variable & var,const Expression & value)1098 void MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1099 this->writeExpression(value, kTopLevel_Precedence);
1100 }
1101
writeName(const String & name)1102 void MetalCodeGenerator::writeName(const String& name) {
1103 if (fReservedWords.find(name) != fReservedWords.end()) {
1104 this->write("_"); // adding underscore before name to avoid conflict with reserved words
1105 }
1106 this->write(name);
1107 }
1108
writeVarDeclarations(const VarDeclarations & decl,bool global)1109 void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
1110 SkASSERT(decl.fVars.size() > 0);
1111 bool wroteType = false;
1112 for (const auto& stmt : decl.fVars) {
1113 VarDeclaration& var = (VarDeclaration&) *stmt;
1114 if (global && !(var.fVar->fModifiers.fFlags & Modifiers::kConst_Flag)) {
1115 continue;
1116 }
1117 if (wroteType) {
1118 this->write(", ");
1119 } else {
1120 this->writeModifiers(var.fVar->fModifiers, global);
1121 this->writeType(decl.fBaseType);
1122 this->write(" ");
1123 wroteType = true;
1124 }
1125 this->writeName(var.fVar->fName);
1126 for (const auto& size : var.fSizes) {
1127 this->write("[");
1128 if (size) {
1129 this->writeExpression(*size, kTopLevel_Precedence);
1130 }
1131 this->write("]");
1132 }
1133 if (var.fValue) {
1134 this->write(" = ");
1135 this->writeVarInitializer(*var.fVar, *var.fValue);
1136 }
1137 }
1138 if (wroteType) {
1139 this->write(";");
1140 }
1141 }
1142
writeStatement(const Statement & s)1143 void MetalCodeGenerator::writeStatement(const Statement& s) {
1144 switch (s.fKind) {
1145 case Statement::kBlock_Kind:
1146 this->writeBlock((Block&) s);
1147 break;
1148 case Statement::kExpression_Kind:
1149 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1150 this->write(";");
1151 break;
1152 case Statement::kReturn_Kind:
1153 this->writeReturnStatement((ReturnStatement&) s);
1154 break;
1155 case Statement::kVarDeclarations_Kind:
1156 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
1157 break;
1158 case Statement::kIf_Kind:
1159 this->writeIfStatement((IfStatement&) s);
1160 break;
1161 case Statement::kFor_Kind:
1162 this->writeForStatement((ForStatement&) s);
1163 break;
1164 case Statement::kWhile_Kind:
1165 this->writeWhileStatement((WhileStatement&) s);
1166 break;
1167 case Statement::kDo_Kind:
1168 this->writeDoStatement((DoStatement&) s);
1169 break;
1170 case Statement::kSwitch_Kind:
1171 this->writeSwitchStatement((SwitchStatement&) s);
1172 break;
1173 case Statement::kBreak_Kind:
1174 this->write("break;");
1175 break;
1176 case Statement::kContinue_Kind:
1177 this->write("continue;");
1178 break;
1179 case Statement::kDiscard_Kind:
1180 this->write("discard_fragment();");
1181 break;
1182 case Statement::kNop_Kind:
1183 this->write(";");
1184 break;
1185 default:
1186 ABORT("unsupported statement: %s", s.description().c_str());
1187 }
1188 }
1189
writeStatements(const std::vector<std::unique_ptr<Statement>> & statements)1190 void MetalCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1191 for (const auto& s : statements) {
1192 if (!s->isEmpty()) {
1193 this->writeStatement(*s);
1194 this->writeLine();
1195 }
1196 }
1197 }
1198
writeBlock(const Block & b)1199 void MetalCodeGenerator::writeBlock(const Block& b) {
1200 this->writeLine("{");
1201 fIndentation++;
1202 this->writeStatements(b.fStatements);
1203 fIndentation--;
1204 this->write("}");
1205 }
1206
writeIfStatement(const IfStatement & stmt)1207 void MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1208 this->write("if (");
1209 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1210 this->write(") ");
1211 this->writeStatement(*stmt.fIfTrue);
1212 if (stmt.fIfFalse) {
1213 this->write(" else ");
1214 this->writeStatement(*stmt.fIfFalse);
1215 }
1216 }
1217
writeForStatement(const ForStatement & f)1218 void MetalCodeGenerator::writeForStatement(const ForStatement& f) {
1219 this->write("for (");
1220 if (f.fInitializer && !f.fInitializer->isEmpty()) {
1221 this->writeStatement(*f.fInitializer);
1222 } else {
1223 this->write("; ");
1224 }
1225 if (f.fTest) {
1226 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1227 }
1228 this->write("; ");
1229 if (f.fNext) {
1230 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1231 }
1232 this->write(") ");
1233 this->writeStatement(*f.fStatement);
1234 }
1235
writeWhileStatement(const WhileStatement & w)1236 void MetalCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1237 this->write("while (");
1238 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1239 this->write(") ");
1240 this->writeStatement(*w.fStatement);
1241 }
1242
writeDoStatement(const DoStatement & d)1243 void MetalCodeGenerator::writeDoStatement(const DoStatement& d) {
1244 this->write("do ");
1245 this->writeStatement(*d.fStatement);
1246 this->write(" while (");
1247 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1248 this->write(");");
1249 }
1250
writeSwitchStatement(const SwitchStatement & s)1251 void MetalCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1252 this->write("switch (");
1253 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1254 this->writeLine(") {");
1255 fIndentation++;
1256 for (const auto& c : s.fCases) {
1257 if (c->fValue) {
1258 this->write("case ");
1259 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1260 this->writeLine(":");
1261 } else {
1262 this->writeLine("default:");
1263 }
1264 fIndentation++;
1265 for (const auto& stmt : c->fStatements) {
1266 this->writeStatement(*stmt);
1267 this->writeLine();
1268 }
1269 fIndentation--;
1270 }
1271 fIndentation--;
1272 this->write("}");
1273 }
1274
writeReturnStatement(const ReturnStatement & r)1275 void MetalCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1276 this->write("return");
1277 if (r.fExpression) {
1278 this->write(" ");
1279 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1280 }
1281 this->write(";");
1282 }
1283
writeHeader()1284 void MetalCodeGenerator::writeHeader() {
1285 this->write("#include <metal_stdlib>\n");
1286 this->write("#include <simd/simd.h>\n");
1287 this->write("using namespace metal;\n");
1288 }
1289
writeUniformStruct()1290 void MetalCodeGenerator::writeUniformStruct() {
1291 for (const auto& e : fProgram) {
1292 if (ProgramElement::kVar_Kind == e.fKind) {
1293 VarDeclarations& decls = (VarDeclarations&) e;
1294 if (!decls.fVars.size()) {
1295 continue;
1296 }
1297 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
1298 if (first.fModifiers.fFlags & Modifiers::kUniform_Flag &&
1299 first.fType.kind() != Type::kSampler_Kind) {
1300 if (-1 == fUniformBuffer) {
1301 this->write("struct Uniforms {\n");
1302 fUniformBuffer = first.fModifiers.fLayout.fSet;
1303 if (-1 == fUniformBuffer) {
1304 fErrors.error(decls.fOffset, "Metal uniforms must have 'layout(set=...)'");
1305 }
1306 } else if (first.fModifiers.fLayout.fSet != fUniformBuffer) {
1307 if (-1 == fUniformBuffer) {
1308 fErrors.error(decls.fOffset, "Metal backend requires all uniforms to have "
1309 "the same 'layout(set=...)'");
1310 }
1311 }
1312 this->write(" ");
1313 this->writeType(first.fType);
1314 this->write(" ");
1315 for (const auto& stmt : decls.fVars) {
1316 VarDeclaration& var = (VarDeclaration&) *stmt;
1317 this->writeName(var.fVar->fName);
1318 }
1319 this->write(";\n");
1320 }
1321 }
1322 }
1323 if (-1 != fUniformBuffer) {
1324 this->write("};\n");
1325 }
1326 }
1327
writeInputStruct()1328 void MetalCodeGenerator::writeInputStruct() {
1329 this->write("struct Inputs {\n");
1330 for (const auto& e : fProgram) {
1331 if (ProgramElement::kVar_Kind == e.fKind) {
1332 VarDeclarations& decls = (VarDeclarations&) e;
1333 if (!decls.fVars.size()) {
1334 continue;
1335 }
1336 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
1337 if (first.fModifiers.fFlags & Modifiers::kIn_Flag &&
1338 -1 == first.fModifiers.fLayout.fBuiltin) {
1339 this->write(" ");
1340 this->writeType(first.fType);
1341 this->write(" ");
1342 for (const auto& stmt : decls.fVars) {
1343 VarDeclaration& var = (VarDeclaration&) *stmt;
1344 this->writeName(var.fVar->fName);
1345 if (-1 != var.fVar->fModifiers.fLayout.fLocation) {
1346 if (fProgram.fKind == Program::kVertex_Kind) {
1347 this->write(" [[attribute(" +
1348 to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
1349 } else if (fProgram.fKind == Program::kFragment_Kind) {
1350 this->write(" [[user(locn" +
1351 to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
1352 }
1353 }
1354 }
1355 this->write(";\n");
1356 }
1357 }
1358 }
1359 this->write("};\n");
1360 }
1361
writeOutputStruct()1362 void MetalCodeGenerator::writeOutputStruct() {
1363 this->write("struct Outputs {\n");
1364 if (fProgram.fKind == Program::kVertex_Kind) {
1365 this->write(" float4 sk_Position [[position]];\n");
1366 } else if (fProgram.fKind == Program::kFragment_Kind) {
1367 this->write(" float4 sk_FragColor [[color(0)]];\n");
1368 }
1369 for (const auto& e : fProgram) {
1370 if (ProgramElement::kVar_Kind == e.fKind) {
1371 VarDeclarations& decls = (VarDeclarations&) e;
1372 if (!decls.fVars.size()) {
1373 continue;
1374 }
1375 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
1376 if (first.fModifiers.fFlags & Modifiers::kOut_Flag &&
1377 -1 == first.fModifiers.fLayout.fBuiltin) {
1378 this->write(" ");
1379 this->writeType(first.fType);
1380 this->write(" ");
1381 for (const auto& stmt : decls.fVars) {
1382 VarDeclaration& var = (VarDeclaration&) *stmt;
1383 this->writeName(var.fVar->fName);
1384 if (fProgram.fKind == Program::kVertex_Kind) {
1385 this->write(" [[user(locn" +
1386 to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
1387 } else if (fProgram.fKind == Program::kFragment_Kind) {
1388 this->write(" [[color(" +
1389 to_string(var.fVar->fModifiers.fLayout.fLocation) +")");
1390 int colorIndex = var.fVar->fModifiers.fLayout.fIndex;
1391 if (colorIndex) {
1392 this->write(", index(" + to_string(colorIndex) + ")");
1393 }
1394 this->write("]]");
1395 }
1396 }
1397 this->write(";\n");
1398 }
1399 }
1400 }
1401 if (fProgram.fKind == Program::kVertex_Kind) {
1402 this->write(" float sk_PointSize;\n");
1403 }
1404 this->write("};\n");
1405 }
1406
writeInterfaceBlocks()1407 void MetalCodeGenerator::writeInterfaceBlocks() {
1408 bool wroteInterfaceBlock = false;
1409 for (const auto& e : fProgram) {
1410 if (ProgramElement::kInterfaceBlock_Kind == e.fKind) {
1411 this->writeInterfaceBlock((InterfaceBlock&) e);
1412 wroteInterfaceBlock = true;
1413 }
1414 }
1415 if (!wroteInterfaceBlock && fProgram.fInputs.fRTHeight) {
1416 this->writeLine("struct sksl_synthetic_uniforms {");
1417 this->writeLine(" float u_skRTHeight;");
1418 this->writeLine("};");
1419 }
1420 }
1421
writeGlobalStruct()1422 void MetalCodeGenerator::writeGlobalStruct() {
1423 bool wroteStructDecl = false;
1424 for (const auto& intf : fInterfaceBlockNameMap) {
1425 if (!wroteStructDecl) {
1426 this->write("struct Globals {\n");
1427 wroteStructDecl = true;
1428 }
1429 fNeedsGlobalStructInit = true;
1430 const auto& intfType = intf.first;
1431 const auto& intfName = intf.second;
1432 this->write(" constant ");
1433 this->write(intfType->fTypeName);
1434 this->write("* ");
1435 this->writeName(intfName);
1436 this->write(";\n");
1437 }
1438 for (const auto& e : fProgram) {
1439 if (ProgramElement::kVar_Kind == e.fKind) {
1440 VarDeclarations& decls = (VarDeclarations&) e;
1441 if (!decls.fVars.size()) {
1442 continue;
1443 }
1444 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
1445 if ((!first.fModifiers.fFlags && -1 == first.fModifiers.fLayout.fBuiltin) ||
1446 first.fType.kind() == Type::kSampler_Kind) {
1447 if (!wroteStructDecl) {
1448 this->write("struct Globals {\n");
1449 wroteStructDecl = true;
1450 }
1451 fNeedsGlobalStructInit = true;
1452 this->write(" ");
1453 this->writeType(first.fType);
1454 this->write(" ");
1455 for (const auto& stmt : decls.fVars) {
1456 VarDeclaration& var = (VarDeclaration&) *stmt;
1457 this->writeName(var.fVar->fName);
1458 if (var.fVar->fType.kind() == Type::kSampler_Kind) {
1459 fTextures.push_back(var.fVar);
1460 this->write(";\n");
1461 this->write(" sampler ");
1462 this->writeName(var.fVar->fName);
1463 this->write(SAMPLER_SUFFIX);
1464 }
1465 if (var.fValue) {
1466 fInitNonConstGlobalVars.push_back(&var);
1467 }
1468 }
1469 this->write(";\n");
1470 }
1471 }
1472 }
1473 if (wroteStructDecl) {
1474 this->write("};\n");
1475 }
1476 }
1477
writeProgramElement(const ProgramElement & e)1478 void MetalCodeGenerator::writeProgramElement(const ProgramElement& e) {
1479 switch (e.fKind) {
1480 case ProgramElement::kExtension_Kind:
1481 break;
1482 case ProgramElement::kVar_Kind: {
1483 VarDeclarations& decl = (VarDeclarations&) e;
1484 if (decl.fVars.size() > 0) {
1485 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
1486 if (-1 == builtin) {
1487 // normal var
1488 this->writeVarDeclarations(decl, true);
1489 this->writeLine();
1490 } else if (SK_FRAGCOLOR_BUILTIN == builtin) {
1491 // ignore
1492 }
1493 }
1494 break;
1495 }
1496 case ProgramElement::kInterfaceBlock_Kind:
1497 // handled in writeInterfaceBlocks, do nothing
1498 break;
1499 case ProgramElement::kFunction_Kind:
1500 this->writeFunction((FunctionDefinition&) e);
1501 break;
1502 case ProgramElement::kModifiers_Kind:
1503 this->writeModifiers(((ModifiersDeclaration&) e).fModifiers, true);
1504 this->writeLine(";");
1505 break;
1506 default:
1507 printf("%s\n", e.description().c_str());
1508 ABORT("unsupported program element");
1509 }
1510 }
1511
requirements(const Expression & e)1512 MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expression& e) {
1513 switch (e.fKind) {
1514 case Expression::kFunctionCall_Kind: {
1515 const FunctionCall& f = (const FunctionCall&) e;
1516 Requirements result = this->requirements(f.fFunction);
1517 for (const auto& e : f.fArguments) {
1518 result |= this->requirements(*e);
1519 }
1520 return result;
1521 }
1522 case Expression::kConstructor_Kind: {
1523 const Constructor& c = (const Constructor&) e;
1524 Requirements result = kNo_Requirements;
1525 for (const auto& e : c.fArguments) {
1526 result |= this->requirements(*e);
1527 }
1528 return result;
1529 }
1530 case Expression::kFieldAccess_Kind: {
1531 const FieldAccess& f = (const FieldAccess&) e;
1532 if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) {
1533 return kGlobals_Requirement;
1534 }
1535 return this->requirements(*((const FieldAccess&) e).fBase);
1536 }
1537 case Expression::kSwizzle_Kind:
1538 return this->requirements(*((const Swizzle&) e).fBase);
1539 case Expression::kBinary_Kind: {
1540 const BinaryExpression& b = (const BinaryExpression&) e;
1541 return this->requirements(*b.fLeft) | this->requirements(*b.fRight);
1542 }
1543 case Expression::kIndex_Kind: {
1544 const IndexExpression& idx = (const IndexExpression&) e;
1545 return this->requirements(*idx.fBase) | this->requirements(*idx.fIndex);
1546 }
1547 case Expression::kPrefix_Kind:
1548 return this->requirements(*((const PrefixExpression&) e).fOperand);
1549 case Expression::kPostfix_Kind:
1550 return this->requirements(*((const PostfixExpression&) e).fOperand);
1551 case Expression::kTernary_Kind: {
1552 const TernaryExpression& t = (const TernaryExpression&) e;
1553 return this->requirements(*t.fTest) | this->requirements(*t.fIfTrue) |
1554 this->requirements(*t.fIfFalse);
1555 }
1556 case Expression::kVariableReference_Kind: {
1557 const VariableReference& v = (const VariableReference&) e;
1558 Requirements result = kNo_Requirements;
1559 if (v.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
1560 result = kGlobals_Requirement | kFragCoord_Requirement;
1561 } else if (Variable::kGlobal_Storage == v.fVariable.fStorage) {
1562 if (v.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
1563 result = kInputs_Requirement;
1564 } else if (v.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
1565 result = kOutputs_Requirement;
1566 } else if (v.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
1567 v.fVariable.fType.kind() != Type::kSampler_Kind) {
1568 result = kUniforms_Requirement;
1569 } else {
1570 result = kGlobals_Requirement;
1571 }
1572 }
1573 return result;
1574 }
1575 default:
1576 return kNo_Requirements;
1577 }
1578 }
1579
requirements(const Statement & s)1580 MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statement& s) {
1581 switch (s.fKind) {
1582 case Statement::kBlock_Kind: {
1583 Requirements result = kNo_Requirements;
1584 for (const auto& child : ((const Block&) s).fStatements) {
1585 result |= this->requirements(*child);
1586 }
1587 return result;
1588 }
1589 case Statement::kVarDeclaration_Kind: {
1590 Requirements result = kNo_Requirements;
1591 const VarDeclaration& var = (const VarDeclaration&) s;
1592 if (var.fValue) {
1593 result = this->requirements(*var.fValue);
1594 }
1595 return result;
1596 }
1597 case Statement::kVarDeclarations_Kind: {
1598 Requirements result = kNo_Requirements;
1599 const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
1600 for (const auto& stmt : decls.fVars) {
1601 result |= this->requirements(*stmt);
1602 }
1603 return result;
1604 }
1605 case Statement::kExpression_Kind:
1606 return this->requirements(*((const ExpressionStatement&) s).fExpression);
1607 case Statement::kReturn_Kind: {
1608 const ReturnStatement& r = (const ReturnStatement&) s;
1609 if (r.fExpression) {
1610 return this->requirements(*r.fExpression);
1611 }
1612 return kNo_Requirements;
1613 }
1614 case Statement::kIf_Kind: {
1615 const IfStatement& i = (const IfStatement&) s;
1616 return this->requirements(*i.fTest) |
1617 this->requirements(*i.fIfTrue) |
1618 (i.fIfFalse ? this->requirements(*i.fIfFalse) : 0);
1619 }
1620 case Statement::kFor_Kind: {
1621 const ForStatement& f = (const ForStatement&) s;
1622 return this->requirements(*f.fInitializer) |
1623 this->requirements(*f.fTest) |
1624 this->requirements(*f.fNext) |
1625 this->requirements(*f.fStatement);
1626 }
1627 case Statement::kWhile_Kind: {
1628 const WhileStatement& w = (const WhileStatement&) s;
1629 return this->requirements(*w.fTest) |
1630 this->requirements(*w.fStatement);
1631 }
1632 case Statement::kDo_Kind: {
1633 const DoStatement& d = (const DoStatement&) s;
1634 return this->requirements(*d.fTest) |
1635 this->requirements(*d.fStatement);
1636 }
1637 case Statement::kSwitch_Kind: {
1638 const SwitchStatement& sw = (const SwitchStatement&) s;
1639 Requirements result = this->requirements(*sw.fValue);
1640 for (const auto& c : sw.fCases) {
1641 for (const auto& st : c->fStatements) {
1642 result |= this->requirements(*st);
1643 }
1644 }
1645 return result;
1646 }
1647 default:
1648 return kNo_Requirements;
1649 }
1650 }
1651
requirements(const FunctionDeclaration & f)1652 MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const FunctionDeclaration& f) {
1653 if (f.fBuiltin) {
1654 return kNo_Requirements;
1655 }
1656 auto found = fRequirements.find(&f);
1657 if (found == fRequirements.end()) {
1658 fRequirements[&f] = kNo_Requirements;
1659 for (const auto& e : fProgram) {
1660 if (ProgramElement::kFunction_Kind == e.fKind) {
1661 const FunctionDefinition& def = (const FunctionDefinition&) e;
1662 if (&def.fDeclaration == &f) {
1663 Requirements reqs = this->requirements(*def.fBody);
1664 fRequirements[&f] = reqs;
1665 return reqs;
1666 }
1667 }
1668 }
1669 }
1670 return found->second;
1671 }
1672
generateCode()1673 bool MetalCodeGenerator::generateCode() {
1674 OutputStream* rawOut = fOut;
1675 fOut = &fHeader;
1676 #ifdef SK_MOLTENVK
1677 fOut->write((const char*) &MVKMagicNum, sizeof(MVKMagicNum));
1678 #endif
1679 fProgramKind = fProgram.fKind;
1680 this->writeHeader();
1681 this->writeUniformStruct();
1682 this->writeInputStruct();
1683 this->writeOutputStruct();
1684 this->writeInterfaceBlocks();
1685 this->writeGlobalStruct();
1686 StringStream body;
1687 fOut = &body;
1688 for (const auto& e : fProgram) {
1689 this->writeProgramElement(e);
1690 }
1691 fOut = rawOut;
1692
1693 write_stringstream(fHeader, *rawOut);
1694 write_stringstream(fExtraFunctions, *rawOut);
1695 write_stringstream(body, *rawOut);
1696 #ifdef SK_MOLTENVK
1697 this->write("\0");
1698 #endif
1699 return true;
1700 }
1701
1702 }
1703