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