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 = &param->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