blob: 3aede1f73dde72cd4450befdfbf6ecfc25e1e6b4 [file] [log] [blame]
Ethan Nicholascc305772017-10-13 16:17:45 -04001/*
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
Timothy Liangb8eeb802018-07-23 16:46:16 -040018#ifdef SK_MOLTENVK
19 static const uint32_t MVKMagicNum = 0x19960412;
20#endif
Timothy Lianga06f2152018-05-24 15:33:31 -040021
Ethan Nicholascc305772017-10-13 16:17:45 -040022namespace SkSL {
23
Timothy Liangee84fe12018-05-18 14:38:19 -040024void MetalCodeGenerator::setupIntrinsics() {
Timothy Liang7d637782018-06-05 09:58:07 -040025#define METAL(x) std::make_pair(kMetal_IntrinsicKind, k ## x ## _MetalIntrinsic)
26#define SPECIAL(x) std::make_pair(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic)
Timothy Lianga06f2152018-05-24 15:33:31 -040027 fIntrinsicMap[String("texture")] = SPECIAL(Texture);
Timothy Liang651286f2018-06-07 09:55:33 -040028 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0dc80872019-02-08 15:46:24 -050029 fIntrinsicMap[String("equal")] = METAL(Equal);
30 fIntrinsicMap[String("notEqual")] = METAL(NotEqual);
Timothy Lianga06f2152018-05-24 15:33:31 -040031 fIntrinsicMap[String("lessThan")] = METAL(LessThan);
32 fIntrinsicMap[String("lessThanEqual")] = METAL(LessThanEqual);
33 fIntrinsicMap[String("greaterThan")] = METAL(GreaterThan);
34 fIntrinsicMap[String("greaterThanEqual")] = METAL(GreaterThanEqual);
Timothy Liangee84fe12018-05-18 14:38:19 -040035}
36
Ethan Nicholascc305772017-10-13 16:17:45 -040037void 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
50void MetalCodeGenerator::writeLine(const char* s) {
51 this->write(s);
52 fOut->writeText(fLineEnding);
53 fAtLineStart = true;
54}
55
56void MetalCodeGenerator::write(const String& s) {
57 this->write(s.c_str());
58}
59
60void MetalCodeGenerator::writeLine(const String& s) {
61 this->writeLine(s.c_str());
62}
63
64void MetalCodeGenerator::writeLine() {
65 this->writeLine("");
66}
67
68void MetalCodeGenerator::writeExtension(const Extension& ext) {
69 this->writeLine("#extension " + ext.fName + " : enable");
70}
71
72void 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++;
Timothy Liangdc89f192018-06-13 09:20:31 -040085 this->writeFields(type.fields(), type.fOffset);
Ethan Nicholascc305772017-10-13 16:17:45 -040086 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;
Timothy Liang43d225f2018-07-19 15:27:13 -040093 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;
Timothy Liangee84fe12018-05-18 14:38:19 -040099 case Type::kSampler_Kind:
Timothy Liang43d225f2018-07-19 15:27:13 -0400100 this->write("texture2d<float> "); // FIXME - support other texture types;
Timothy Liangee84fe12018-05-18 14:38:19 -0400101 break;
Ethan Nicholascc305772017-10-13 16:17:45 -0400102 default:
Timothy Liang43d225f2018-07-19 15:27:13 -0400103 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");
Timothy Liang7d637782018-06-05 09:58:07 -0400110 } else {
111 this->write(type.name());
112 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400113 }
114}
115
116void 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:
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500125 this->writeConstructor((Constructor&) expr, parentPrecedence);
Ethan Nicholascc305772017-10-13 16:17:45 -0400126 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
Timothy Liang6403b0e2018-05-17 10:40:04 -0400165void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
Timothy Liang7d637782018-06-05 09:58:07 -0400166 auto i = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400167 SkASSERT(i != fIntrinsicMap.end());
Timothy Liang7d637782018-06-05 09:58:07 -0400168 Intrinsic intrinsic = i->second;
169 int32_t intrinsicId = intrinsic.second;
170 switch (intrinsic.first) {
Timothy Liang6403b0e2018-05-17 10:40:04 -0400171 case kSpecial_IntrinsicKind:
172 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId);
Timothy Lianga06f2152018-05-24 15:33:31 -0400173 break;
174 case kMetal_IntrinsicKind:
175 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
176 switch ((MetalIntrinsic) intrinsicId) {
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500177 case kEqual_MetalIntrinsic:
178 this->write(" == ");
179 break;
180 case kNotEqual_MetalIntrinsic:
181 this->write(" != ");
182 break;
Timothy Lianga06f2152018-05-24 15:33:31 -0400183 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;
Timothy Liang6403b0e2018-05-17 10:40:04 -0400200 default:
201 ABORT("unsupported intrinsic kind");
202 }
203}
204
Ethan Nicholascc305772017-10-13 16:17:45 -0400205void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Timothy Liang6403b0e2018-05-17 10:40:04 -0400206 const auto& entry = fIntrinsicMap.find(c.fFunction.fName);
207 if (entry != fIntrinsicMap.end()) {
208 this->writeIntrinsicCall(c);
209 return;
210 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400211 if (c.fFunction.fBuiltin && "atan" == c.fFunction.fName && 2 == c.fArguments.size()) {
212 this->write("atan2");
Timothy Lianga06f2152018-05-24 15:33:31 -0400213 } else if (c.fFunction.fBuiltin && "inversesqrt" == c.fFunction.fName) {
214 this->write("rsqrt");
Chris Daltondba7aab2018-11-15 10:57:49 -0500215 } else if (c.fFunction.fBuiltin && "inverse" == c.fFunction.fName) {
216 SkASSERT(c.fArguments.size() == 1);
217 this->writeInverseHack(*c.fArguments[0]);
Timothy Liang7d637782018-06-05 09:58:07 -0400218 } else if (c.fFunction.fBuiltin && "dFdx" == c.fFunction.fName) {
219 this->write("dfdx");
220 } else if (c.fFunction.fBuiltin && "dFdy" == c.fFunction.fName) {
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700221 // Flipping Y also negates the Y derivatives.
222 this->write((fProgram.fSettings.fFlipY) ? "-dfdy" : "dfdy");
Ethan Nicholascc305772017-10-13 16:17:45 -0400223 } else {
Timothy Liang651286f2018-06-07 09:55:33 -0400224 this->writeName(c.fFunction.fName);
Ethan Nicholascc305772017-10-13 16:17:45 -0400225 }
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 }
Timothy Liangee84fe12018-05-18 14:38:19 -0400242 if (this->requirements(c.fFunction) & kGlobals_Requirement) {
243 this->write(separator);
244 this->write("_globals");
245 separator = ", ";
246 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400247 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
Chris Daltondba7aab2018-11-15 10:57:49 -0500259void MetalCodeGenerator::writeInverseHack(const Expression& mat) {
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500260 String typeName = mat.fType.name();
261 String name = typeName + "_inverse";
262 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
Chris Daltondba7aab2018-11-15 10:57:49 -0500263 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
264 fWrittenIntrinsics.insert(name);
265 fExtraFunctions.writeText((
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500266 typeName + " " + name + "(" + typeName + " m) {"
Chris Daltondba7aab2018-11-15 10:57:49 -0500267 " return float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]) * (1/determinant(m));"
268 "}"
269 ).c_str());
270 }
271 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500272 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 }
Chris Daltondba7aab2018-11-15 10:57:49 -0500336 this->write(name);
337}
338
Timothy Liang6403b0e2018-05-17 10:40:04 -0400339void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) {
340 switch (kind) {
341 case kTexture_SpecialIntrinsic:
Timothy Liangee84fe12018-05-18 14:38:19 -0400342 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
Timothy Lianga06f2152018-05-24 15:33:31 -0400343 this->write(".sample(");
344 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
345 this->write(SAMPLER_SUFFIX);
346 this->write(", ");
Timothy Liang6403b0e2018-05-17 10:40:04 -0400347 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
Timothy Liangee84fe12018-05-18 14:38:19 -0400348 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
349 this->write(".xy)"); // FIXME - add projection functionality
350 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400351 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Timothy Liangee84fe12018-05-18 14:38:19 -0400352 this->write(")");
353 }
Timothy Liang6403b0e2018-05-17 10:40:04 -0400354 break;
Timothy Liang651286f2018-06-07 09:55:33 -0400355 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;
Timothy Liang6403b0e2018-05-17 10:40:04 -0400367 default:
368 ABORT("unsupported special intrinsic kind");
369 }
370}
371
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500372// If it hasn't already been written, writes a constructor for 'matrix' which takes a single value
373// of type 'arg'.
374String MetalCodeGenerator::getMatrixConstructHelper(const Type& matrix, const Type& arg) {
375 String key = matrix.name() + arg.name();
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500376 auto found = fHelpers.find(key);
377 if (found != fHelpers.end()) {
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500378 return found->second;
Ethan Nicholascc305772017-10-13 16:17:45 -0400379 }
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500380 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");
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500407 } 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) {
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500435 // 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 );
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500443 } else {
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500444 SkASSERT(false);
445 name = "<error>";
446 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500447 fHelpers[key] = name;
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500448 return name;
449}
450
451bool 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 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500458 return t1.isFloat() && t2.isFloat();
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500459}
460
461void 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 = ", ";
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500481 if (Type::kMatrix_Kind == c.fType.kind() && arg->fType.columns() != c.fType.rows()) {
482 // merge scalars and smaller vectors together
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500483 if (!scalarCount) {
484 this->writeType(c.fType.componentType());
485 this->write(to_string(c.fType.rows()));
486 this->write("(");
487 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500488 scalarCount += arg->fType.columns();
Ethan Nicholas842d31b2019-01-22 10:59:11 -0500489 }
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 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400498}
499
500void MetalCodeGenerator::writeFragCoord() {
Jim Van Verth6bc650e2019-02-07 14:53:23 -0500501 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 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400507}
508
509void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
510 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
511 case SK_FRAGCOLOR_BUILTIN:
Timothy Liang7d637782018-06-05 09:58:07 -0400512 this->write("_out->sk_FragColor");
Ethan Nicholascc305772017-10-13 16:17:45 -0400513 break;
Timothy Liang6403b0e2018-05-17 10:40:04 -0400514 case SK_FRAGCOORD_BUILTIN:
515 this->writeFragCoord();
516 break;
Timothy Liangdc89f192018-06-13 09:20:31 -0400517 case SK_VERTEXID_BUILTIN:
518 this->write("sk_VertexID");
519 break;
520 case SK_INSTANCEID_BUILTIN:
521 this->write("sk_InstanceID");
522 break;
Timothy Liang7b8875d2018-08-10 09:42:31 -0400523 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;
Ethan Nicholascc305772017-10-13 16:17:45 -0400528 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) {
Timothy Liangee84fe12018-05-18 14:38:19 -0400533 this->write("_out->");
Timothy Lianga06f2152018-05-24 15:33:31 -0400534 } else if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
535 ref.fVariable.fType.kind() != Type::kSampler_Kind) {
Ethan Nicholascc305772017-10-13 16:17:45 -0400536 this->write("_uniforms.");
537 } else {
Timothy Liangee84fe12018-05-18 14:38:19 -0400538 this->write("_globals->");
Ethan Nicholascc305772017-10-13 16:17:45 -0400539 }
540 }
Timothy Liang651286f2018-06-07 09:55:33 -0400541 this->writeName(ref.fVariable.fName);
Ethan Nicholascc305772017-10-13 16:17:45 -0400542 }
543}
544
545void 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
552void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
Timothy Liang7d637782018-06-05 09:58:07 -0400553 const Type::Field* field = &f.fBase->fType.fields()[f.fFieldIndex];
Ethan Nicholascc305772017-10-13 16:17:45 -0400554 if (FieldAccess::kDefault_OwnerKind == f.fOwnerKind) {
555 this->writeExpression(*f.fBase, kPostfix_Precedence);
556 this->write(".");
557 }
Timothy Liang7d637782018-06-05 09:58:07 -0400558 switch (field->fModifiers.fLayout.fBuiltin) {
Ethan Nicholascc305772017-10-13 16:17:45 -0400559 case SK_CLIPDISTANCE_BUILTIN:
560 this->write("gl_ClipDistance");
561 break;
562 case SK_POSITION_BUILTIN:
Timothy Liangb8eeb802018-07-23 16:46:16 -0400563 this->write("_out->sk_Position");
Ethan Nicholascc305772017-10-13 16:17:45 -0400564 break;
565 default:
Timothy Liang7d637782018-06-05 09:58:07 -0400566 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 }
Timothy Liang651286f2018-06-07 09:55:33 -0400574 this->writeName(field->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -0400575 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400576 }
577}
578
579void MetalCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
Ethan Nicholas5476f2e2019-03-07 15:11:31 -0500580 int last = swizzle.fComponents.back();
581 if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
582 this->writeType(swizzle.fType);
583 this->write("(");
584 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400585 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
586 this->write(".");
587 for (int c : swizzle.fComponents) {
Ethan Nicholas5476f2e2019-03-07 15:11:31 -0500588 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)");
Ethan Nicholascc305772017-10-13 16:17:45 -0400597 }
598}
599
600MetalCodeGenerator::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
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500640void 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
Ethan Nicholascc305772017-10-13 16:17:45 -0400652void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
653 Precedence parentPrecedence) {
654 Precedence precedence = GetBinaryPrecedence(b.fOperator);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500655 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) {
Ethan Nicholascc305772017-10-13 16:17:45 -0400673 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 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500683 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 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400687 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);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400700 SkASSERT(op.endsWith("="));
Ethan Nicholascc305772017-10-13 16:17:45 -0400701 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);
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500707 if (needParens) {
Ethan Nicholascc305772017-10-13 16:17:45 -0400708 this->write(")");
709 }
710}
711
712void 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
727void 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
739void 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
751void MetalCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
752 this->write(b.fValue ? "true" : "false");
753}
754
755void 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
763void MetalCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
764 this->write(to_string(f.fValue));
765}
766
767void MetalCodeGenerator::writeSetting(const Setting& s) {
768 ABORT("internal error; setting was not folded to a constant during compilation\n");
769}
770
771void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
772 const char* separator = "";
773 if ("main" == f.fDeclaration.fName) {
774 switch (fProgram.fKind) {
775 case Program::kFragment_Kind:
Timothy Liangb8eeb802018-07-23 16:46:16 -0400776#ifdef SK_MOLTENVK
777 this->write("fragment Outputs main0");
778#else
779 this->write("fragment Outputs fragmentMain");
780#endif
Ethan Nicholascc305772017-10-13 16:17:45 -0400781 break;
782 case Program::kVertex_Kind:
Timothy Liangb8eeb802018-07-23 16:46:16 -0400783#ifdef SK_MOLTENVK
Timothy Lianga06f2152018-05-24 15:33:31 -0400784 this->write("vertex Outputs main0");
Timothy Liangb8eeb802018-07-23 16:46:16 -0400785#else
786 this->write("vertex Outputs vertexMain");
787#endif
Ethan Nicholascc305772017-10-13 16:17:45 -0400788 break;
789 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400790 SkASSERT(false);
Ethan Nicholascc305772017-10-13 16:17:45 -0400791 }
792 this->write("(Inputs _in [[stage_in]]");
793 if (-1 != fUniformBuffer) {
794 this->write(", constant Uniforms& _uniforms [[buffer(" +
795 to_string(fUniformBuffer) + ")]]");
796 }
Timothy Liang6403b0e2018-05-17 10:40:04 -0400797 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 }
Timothy Liangee84fe12018-05-18 14:38:19 -0400803 for (const auto& stmt: decls.fVars) {
Timothy Liang6403b0e2018-05-17 10:40:04 -0400804 VarDeclaration& var = (VarDeclaration&) *stmt;
Timothy Liangee84fe12018-05-18 14:38:19 -0400805 if (var.fVar->fType.kind() == Type::kSampler_Kind) {
Timothy Liang7d637782018-06-05 09:58:07 -0400806 this->write(", texture2d<float> "); // FIXME - support other texture types
Timothy Liang651286f2018-06-07 09:55:33 -0400807 this->writeName(var.fVar->fName);
Timothy Liangee84fe12018-05-18 14:38:19 -0400808 this->write("[[texture(");
Timothy Lianga06f2152018-05-24 15:33:31 -0400809 this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
810 this->write(")]]");
811 this->write(", sampler ");
Timothy Liang651286f2018-06-07 09:55:33 -0400812 this->writeName(var.fVar->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -0400813 this->write(SAMPLER_SUFFIX);
814 this->write("[[sampler(");
815 this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
Timothy Liangee84fe12018-05-18 14:38:19 -0400816 this->write(")]]");
817 }
Timothy Liang6403b0e2018-05-17 10:40:04 -0400818 }
Timothy Lianga06f2152018-05-24 15:33:31 -0400819 } 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(");
Timothy Liang057c3902018-08-08 10:48:45 -0400829#ifdef SK_MOLTENVK
Timothy Liang7d637782018-06-05 09:58:07 -0400830 this->write(to_string(intf.fVariable.fModifiers.fLayout.fSet));
Timothy Liang057c3902018-08-08 10:48:45 -0400831#else
832 this->write(to_string(intf.fVariable.fModifiers.fLayout.fBinding));
833#endif
Timothy Lianga06f2152018-05-24 15:33:31 -0400834 this->write(")]]");
Timothy Liang6403b0e2018-05-17 10:40:04 -0400835 }
836 }
Jim Van Verth6bc650e2019-02-07 14:53:23 -0500837 if (fProgram.fKind == Program::kFragment_Kind) {
838 if (fProgram.fInputs.fRTHeight && fInterfaceBlockNameMap.empty()) {
Timothy Liang5422f9a2018-08-10 10:57:55 -0400839#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 }
Timothy Liang7b8875d2018-08-10 09:42:31 -0400845 this->write(", bool _frontFacing [[front_facing]]");
Timothy Liang7d637782018-06-05 09:58:07 -0400846 this->write(", float4 _fragCoord [[position]]");
Timothy Liangdc89f192018-06-13 09:20:31 -0400847 } else if (fProgram.fKind == Program::kVertex_Kind) {
848 this->write(", uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
Timothy Liang7d637782018-06-05 09:58:07 -0400849 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400850 separator = ", ";
851 } else {
852 this->writeType(f.fDeclaration.fReturnType);
Timothy Liang651286f2018-06-07 09:55:33 -0400853 this->write(" ");
854 this->writeName(f.fDeclaration.fName);
855 this->write("(");
Ethan Nicholascc305772017-10-13 16:17:45 -0400856 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);
Timothy Liangee84fe12018-05-18 14:38:19 -0400862 this->write("thread Outputs* _out");
Ethan Nicholascc305772017-10-13 16:17:45 -0400863 separator = ", ";
864 }
865 if (this->requirements(f.fDeclaration) & kUniforms_Requirement) {
866 this->write(separator);
867 this->write("Uniforms _uniforms");
868 separator = ", ";
869 }
Timothy Liangee84fe12018-05-18 14:38:19 -0400870 if (this->requirements(f.fDeclaration) & kGlobals_Requirement) {
871 this->write(separator);
872 this->write("thread Globals* _globals");
873 separator = ", ";
874 }
Ethan Nicholascc305772017-10-13 16:17:45 -0400875 }
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 }
Timothy Liang651286f2018-06-07 09:55:33 -0400890 this->write(" ");
891 this->writeName(param->fName);
Ethan Nicholascc305772017-10-13 16:17:45 -0400892 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
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400902 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
Brian Salomondc092132018-04-04 10:14:16 -0400903
Ethan Nicholascc305772017-10-13 16:17:45 -0400904 if ("main" == f.fDeclaration.fName) {
Timothy Liangee84fe12018-05-18 14:38:19 -0400905 if (fNeedsGlobalStructInit) {
906 this->writeLine(" Globals globalStruct;");
907 this->writeLine(" thread Globals* _globals = &globalStruct;");
Timothy Liang7d637782018-06-05 09:58:07 -0400908 for (const auto& intf: fInterfaceBlockNameMap) {
909 const auto& intfName = intf.second;
910 this->write(" _globals->");
Timothy Liang651286f2018-06-07 09:55:33 -0400911 this->writeName(intfName);
Timothy Liang7d637782018-06-05 09:58:07 -0400912 this->write(" = &");
Timothy Liang651286f2018-06-07 09:55:33 -0400913 this->writeName(intfName);
Timothy Liang7d637782018-06-05 09:58:07 -0400914 this->write(";\n");
915 }
Timothy Lianga06f2152018-05-24 15:33:31 -0400916 for (const auto& var: fInitNonConstGlobalVars) {
Timothy Liangee84fe12018-05-18 14:38:19 -0400917 this->write(" _globals->");
Timothy Liang651286f2018-06-07 09:55:33 -0400918 this->writeName(var->fVar->fName);
Timothy Liangee84fe12018-05-18 14:38:19 -0400919 this->write(" = ");
920 this->writeVarInitializer(*var->fVar, *var->fValue);
921 this->writeLine(";");
922 }
Timothy Lianga06f2152018-05-24 15:33:31 -0400923 for (const auto& texture: fTextures) {
Timothy Liangee84fe12018-05-18 14:38:19 -0400924 this->write(" _globals->");
Timothy Liang651286f2018-06-07 09:55:33 -0400925 this->writeName(texture->fName);
Timothy Liangee84fe12018-05-18 14:38:19 -0400926 this->write(" = ");
Timothy Liang651286f2018-06-07 09:55:33 -0400927 this->writeName(texture->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -0400928 this->write(";\n");
929 this->write(" _globals->");
Timothy Liang651286f2018-06-07 09:55:33 -0400930 this->writeName(texture->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -0400931 this->write(SAMPLER_SUFFIX);
932 this->write(" = ");
Timothy Liang651286f2018-06-07 09:55:33 -0400933 this->writeName(texture->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -0400934 this->write(SAMPLER_SUFFIX);
Timothy Liangee84fe12018-05-18 14:38:19 -0400935 this->write(";\n");
936 }
Timothy Liang6403b0e2018-05-17 10:40:04 -0400937 }
Timothy Liang7d637782018-06-05 09:58:07 -0400938 this->writeLine(" Outputs _outputStruct;");
939 this->writeLine(" thread Outputs* _out = &_outputStruct;");
Ethan Nicholascc305772017-10-13 16:17:45 -0400940 }
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:
Timothy Liang7d637782018-06-05 09:58:07 -0400950 this->writeLine("return *_out;");
Ethan Nicholascc305772017-10-13 16:17:45 -0400951 break;
952 case Program::kVertex_Kind:
Timothy Liangb8eeb802018-07-23 16:46:16 -0400953 this->writeLine("_out->sk_Position.y = -_out->sk_Position.y;");
Timothy Lianga06f2152018-05-24 15:33:31 -0400954 this->writeLine("return *_out;"); // FIXME - detect if function already has return
Ethan Nicholascc305772017-10-13 16:17:45 -0400955 break;
956 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400957 SkASSERT(false);
Ethan Nicholascc305772017-10-13 16:17:45 -0400958 }
959 }
960 fIndentation--;
961 this->writeLine("}");
962
963 fOut = oldOut;
964 this->write(fFunctionHeader);
965 this->write(buffer.str());
966}
967
968void 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) {
Timothy Liangee84fe12018-05-18 14:38:19 -0400974 this->write("constant ");
Ethan Nicholascc305772017-10-13 16:17:45 -0400975 }
976}
977
978void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
979 if ("sk_PerVertex" == intf.fTypeName) {
980 return;
981 }
982 this->writeModifiers(intf.fVariable.fModifiers, true);
Timothy Liangdc89f192018-06-13 09:20:31 -0400983 this->write("struct ");
Ethan Nicholascc305772017-10-13 16:17:45 -0400984 this->writeLine(intf.fTypeName + " {");
Ethan Nicholascc305772017-10-13 16:17:45 -0400985 const Type* structType = &intf.fVariable.fType;
Timothy Lianga06f2152018-05-24 15:33:31 -0400986 fWrittenStructs.push_back(structType);
Ethan Nicholascc305772017-10-13 16:17:45 -0400987 while (Type::kArray_Kind == structType->kind()) {
988 structType = &structType->componentType();
989 }
Timothy Liangdc89f192018-06-13 09:20:31 -0400990 fIndentation++;
991 writeFields(structType->fields(), structType->fOffset, &intf);
Jim Van Verth3d482992019-02-07 10:48:05 -0500992 if (fProgram.fInputs.fRTHeight) {
Timothy Liang7d637782018-06-05 09:58:07 -0400993 this->writeLine("float u_skRTHeight;");
Ethan Nicholascc305772017-10-13 16:17:45 -0400994 }
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 }
Timothy Lianga06f2152018-05-24 15:33:31 -04001007 fInterfaceBlockNameMap[&intf] = intf.fInstanceName;
1008 } else {
Timothy Liang7d637782018-06-05 09:58:07 -04001009 fInterfaceBlockNameMap[&intf] = "_anonInterface" + to_string(fAnonInterfaceCount++);
Ethan Nicholascc305772017-10-13 16:17:45 -04001010 }
1011 this->writeLine(";");
1012}
1013
Timothy Liangdc89f192018-06-13 09:20:31 -04001014void MetalCodeGenerator::writeFields(const std::vector<Type::Field>& fields, int parentOffset,
1015 const InterfaceBlock* parentIntf) {
Timothy Liang609fbe32018-08-10 16:40:49 -04001016#ifdef SK_MOLTENVK
Timothy Liangdc89f192018-06-13 09:20:31 -04001017 MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
Timothy Liang609fbe32018-08-10 16:40:49 -04001018#else
1019 MemoryLayout memoryLayout(MemoryLayout::kMetal_Standard);
1020#endif
Timothy Liangdc89f192018-06-13 09:20:31 -04001021 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 }
Timothy Liang609fbe32018-08-10 16:40:49 -04001045#ifdef SK_MOLTENVK
Timothy Liangdc89f192018-06-13 09:20:31 -04001046 if (fieldType->kind() == Type::kVector_Kind &&
1047 fieldType->columns() == 3) {
Timothy Liang609fbe32018-08-10 16:40:49 -04001048 SkASSERT(memoryLayout.size(*fieldType) == 3);
Timothy Liangdc89f192018-06-13 09:20:31 -04001049 // 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.
Timothy Liang609fbe32018-08-10 16:40:49 -04001052
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.
Timothy Liangdc89f192018-06-13 09:20:31 -04001057 this->write(PACKED_PREFIX);
1058 }
Timothy Liang609fbe32018-08-10 16:40:49 -04001059#endif
Timothy Liangdc89f192018-06-13 09:20:31 -04001060 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
Ethan Nicholascc305772017-10-13 16:17:45 -04001084void MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1085 this->writeExpression(value, kTopLevel_Precedence);
1086}
1087
Timothy Liang651286f2018-06-07 09:55:33 -04001088void 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
Ethan Nicholascc305772017-10-13 16:17:45 -04001095void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001096 SkASSERT(decl.fVars.size() > 0);
Ethan Nicholascc305772017-10-13 16:17:45 -04001097 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001098 for (const auto& stmt : decl.fVars) {
1099 VarDeclaration& var = (VarDeclaration&) *stmt;
Timothy Liangee84fe12018-05-18 14:38:19 -04001100 if (global && !(var.fVar->fModifiers.fFlags & Modifiers::kConst_Flag)) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001101 continue;
1102 }
1103 if (wroteType) {
1104 this->write(", ");
1105 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001106 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholascc305772017-10-13 16:17:45 -04001107 this->writeType(decl.fBaseType);
1108 this->write(" ");
1109 wroteType = true;
1110 }
Timothy Liang651286f2018-06-07 09:55:33 -04001111 this->writeName(var.fVar->fName);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001112 for (const auto& size : var.fSizes) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001113 this->write("[");
1114 if (size) {
1115 this->writeExpression(*size, kTopLevel_Precedence);
1116 }
1117 this->write("]");
1118 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001119 if (var.fValue) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001120 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001121 this->writeVarInitializer(*var.fVar, *var.fValue);
Ethan Nicholascc305772017-10-13 16:17:45 -04001122 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001123 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001124 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
1137void 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:
Timothy Lianga06f2152018-05-24 15:33:31 -04001174 this->write("discard_fragment();");
Ethan Nicholascc305772017-10-13 16:17:45 -04001175 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
1184void 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
1193void MetalCodeGenerator::writeBlock(const Block& b) {
1194 this->writeLine("{");
1195 fIndentation++;
1196 this->writeStatements(b.fStatements);
1197 fIndentation--;
1198 this->write("}");
1199}
1200
1201void 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
1212void 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
1230void 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
1237void 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
1245void 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
1269void 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
1278void 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
1284void MetalCodeGenerator::writeUniformStruct() {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001285 for (const auto& e : fProgram) {
1286 if (ProgramElement::kVar_Kind == e.fKind) {
1287 VarDeclarations& decls = (VarDeclarations&) e;
Ethan Nicholascc305772017-10-13 16:17:45 -04001288 if (!decls.fVars.size()) {
1289 continue;
1290 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001291 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
Timothy Lianga06f2152018-05-24 15:33:31 -04001292 if (first.fModifiers.fFlags & Modifiers::kUniform_Flag &&
1293 first.fType.kind() != Type::kSampler_Kind) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001294 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(" ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001309 for (const auto& stmt : decls.fVars) {
1310 VarDeclaration& var = (VarDeclaration&) *stmt;
Timothy Liang651286f2018-06-07 09:55:33 -04001311 this->writeName(var.fVar->fName);
Ethan Nicholascc305772017-10-13 16:17:45 -04001312 }
1313 this->write(";\n");
1314 }
1315 }
1316 }
1317 if (-1 != fUniformBuffer) {
1318 this->write("};\n");
1319 }
1320}
1321
1322void MetalCodeGenerator::writeInputStruct() {
1323 this->write("struct Inputs {\n");
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001324 for (const auto& e : fProgram) {
1325 if (ProgramElement::kVar_Kind == e.fKind) {
1326 VarDeclarations& decls = (VarDeclarations&) e;
Ethan Nicholascc305772017-10-13 16:17:45 -04001327 if (!decls.fVars.size()) {
1328 continue;
1329 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001330 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
Ethan Nicholascc305772017-10-13 16:17:45 -04001331 if (first.fModifiers.fFlags & Modifiers::kIn_Flag &&
1332 -1 == first.fModifiers.fLayout.fBuiltin) {
1333 this->write(" ");
1334 this->writeType(first.fType);
1335 this->write(" ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001336 for (const auto& stmt : decls.fVars) {
1337 VarDeclaration& var = (VarDeclaration&) *stmt;
Timothy Liang651286f2018-06-07 09:55:33 -04001338 this->writeName(var.fVar->fName);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001339 if (-1 != var.fVar->fModifiers.fLayout.fLocation) {
Timothy Liang7d637782018-06-05 09:58:07 -04001340 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 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001347 }
1348 }
1349 this->write(";\n");
1350 }
1351 }
1352 }
1353 this->write("};\n");
1354}
1355
1356void MetalCodeGenerator::writeOutputStruct() {
1357 this->write("struct Outputs {\n");
Timothy Liang7d637782018-06-05 09:58:07 -04001358 if (fProgram.fKind == Program::kVertex_Kind) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001359 this->write(" float4 sk_Position [[position]];\n");
Timothy Liang7d637782018-06-05 09:58:07 -04001360 } else if (fProgram.fKind == Program::kFragment_Kind) {
Timothy Liangde0be802018-08-10 13:48:08 -04001361 this->write(" float4 sk_FragColor [[color(0)]];\n");
Timothy Liang7d637782018-06-05 09:58:07 -04001362 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001363 for (const auto& e : fProgram) {
1364 if (ProgramElement::kVar_Kind == e.fKind) {
1365 VarDeclarations& decls = (VarDeclarations&) e;
Ethan Nicholascc305772017-10-13 16:17:45 -04001366 if (!decls.fVars.size()) {
1367 continue;
1368 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001369 const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
Ethan Nicholascc305772017-10-13 16:17:45 -04001370 if (first.fModifiers.fFlags & Modifiers::kOut_Flag &&
1371 -1 == first.fModifiers.fLayout.fBuiltin) {
1372 this->write(" ");
1373 this->writeType(first.fType);
1374 this->write(" ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001375 for (const auto& stmt : decls.fVars) {
1376 VarDeclaration& var = (VarDeclaration&) *stmt;
Timothy Liang651286f2018-06-07 09:55:33 -04001377 this->writeName(var.fVar->fName);
Timothy Liang7d637782018-06-05 09:58:07 -04001378 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(" +
Timothy Liangde0be802018-08-10 13:48:08 -04001383 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("]]");
Timothy Liang7d637782018-06-05 09:58:07 -04001389 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001390 }
1391 this->write(";\n");
1392 }
1393 }
Timothy Liang7d637782018-06-05 09:58:07 -04001394 }
1395 if (fProgram.fKind == Program::kVertex_Kind) {
1396 this->write(" float sk_PointSize;\n");
1397 }
1398 this->write("};\n");
1399}
1400
1401void 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 }
Jim Van Verth3d482992019-02-07 10:48:05 -05001409 if (!wroteInterfaceBlock && fProgram.fInputs.fRTHeight) {
Timothy Liang7d637782018-06-05 09:58:07 -04001410 this->writeLine("struct sksl_synthetic_uniforms {");
1411 this->writeLine(" float u_skRTHeight;");
1412 this->writeLine("};");
1413 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001414}
1415
Timothy Liangee84fe12018-05-18 14:38:19 -04001416void MetalCodeGenerator::writeGlobalStruct() {
1417 bool wroteStructDecl = false;
Timothy Liang7d637782018-06-05 09:58:07 -04001418 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("* ");
Timothy Liang651286f2018-06-07 09:55:33 -04001429 this->writeName(intfName);
Timothy Liang7d637782018-06-05 09:58:07 -04001430 this->write(";\n");
1431 }
Timothy Liangee84fe12018-05-18 14:38:19 -04001432 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;
Timothy Lianga06f2152018-05-24 15:33:31 -04001439 if ((!first.fModifiers.fFlags && -1 == first.fModifiers.fLayout.fBuiltin) ||
1440 first.fType.kind() == Type::kSampler_Kind) {
Timothy Liangee84fe12018-05-18 14:38:19 -04001441 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;
Timothy Liang651286f2018-06-07 09:55:33 -04001451 this->writeName(var.fVar->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -04001452 if (var.fVar->fType.kind() == Type::kSampler_Kind) {
1453 fTextures.push_back(var.fVar);
1454 this->write(";\n");
1455 this->write(" sampler ");
Timothy Liang651286f2018-06-07 09:55:33 -04001456 this->writeName(var.fVar->fName);
Timothy Lianga06f2152018-05-24 15:33:31 -04001457 this->write(SAMPLER_SUFFIX);
1458 }
Timothy Liangee84fe12018-05-18 14:38:19 -04001459 if (var.fValue) {
1460 fInitNonConstGlobalVars.push_back(&var);
1461 }
1462 }
1463 this->write(";\n");
1464 }
1465 }
1466 }
Timothy Liangee84fe12018-05-18 14:38:19 -04001467 if (wroteStructDecl) {
1468 this->write("};\n");
1469 }
1470}
1471
Ethan Nicholascc305772017-10-13 16:17:45 -04001472void 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) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001479 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholascc305772017-10-13 16:17:45 -04001480 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:
Timothy Liang7d637782018-06-05 09:58:07 -04001491 // handled in writeInterfaceBlocks, do nothing
Ethan Nicholascc305772017-10-13 16:17:45 -04001492 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
1506MetalCodeGenerator::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 }
Timothy Liang7d637782018-06-05 09:58:07 -04001524 case Expression::kFieldAccess_Kind: {
1525 const FieldAccess& f = (const FieldAccess&) e;
1526 if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) {
1527 return kGlobals_Requirement;
1528 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001529 return this->requirements(*((const FieldAccess&) e).fBase);
Timothy Liang7d637782018-06-05 09:58:07 -04001530 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001531 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;
Timothy Lianga06f2152018-05-24 15:33:31 -04001560 } else if (v.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
1561 v.fVariable.fType.kind() != Type::kSampler_Kind) {
Ethan Nicholascc305772017-10-13 16:17:45 -04001562 result = kUniforms_Requirement;
Timothy Liangee84fe12018-05-18 14:38:19 -04001563 } else {
1564 result = kGlobals_Requirement;
Ethan Nicholascc305772017-10-13 16:17:45 -04001565 }
1566 }
1567 return result;
1568 }
1569 default:
1570 return kNo_Requirements;
1571 }
1572}
1573
1574MetalCodeGenerator::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 }
Timothy Liang7d637782018-06-05 09:58:07 -04001583 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 }
Ethan Nicholascc305772017-10-13 16:17:45 -04001599 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
1646MetalCodeGenerator::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()) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001652 for (const auto& e : fProgram) {
1653 if (ProgramElement::kFunction_Kind == e.fKind) {
1654 const FunctionDefinition& def = (const FunctionDefinition&) e;
Ethan Nicholascc305772017-10-13 16:17:45 -04001655 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
Timothy Liangb8eeb802018-07-23 16:46:16 -04001666bool MetalCodeGenerator::generateCode() {
Ethan Nicholascc305772017-10-13 16:17:45 -04001667 OutputStream* rawOut = fOut;
1668 fOut = &fHeader;
Timothy Liangb8eeb802018-07-23 16:46:16 -04001669#ifdef SK_MOLTENVK
1670 fOut->write((const char*) &MVKMagicNum, sizeof(MVKMagicNum));
1671#endif
Ethan Nicholascc305772017-10-13 16:17:45 -04001672 fProgramKind = fProgram.fKind;
1673 this->writeHeader();
1674 this->writeUniformStruct();
1675 this->writeInputStruct();
Timothy Liang7d637782018-06-05 09:58:07 -04001676 this->writeOutputStruct();
1677 this->writeInterfaceBlocks();
Timothy Liangee84fe12018-05-18 14:38:19 -04001678 this->writeGlobalStruct();
Ethan Nicholascc305772017-10-13 16:17:45 -04001679 StringStream body;
1680 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001681 for (const auto& e : fProgram) {
1682 this->writeProgramElement(e);
Ethan Nicholascc305772017-10-13 16:17:45 -04001683 }
1684 fOut = rawOut;
1685
1686 write_stringstream(fHeader, *rawOut);
Chris Daltondba7aab2018-11-15 10:57:49 -05001687 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholascc305772017-10-13 16:17:45 -04001688 write_stringstream(body, *rawOut);
Timothy Liangb8eeb802018-07-23 16:46:16 -04001689#ifdef SK_MOLTENVK
1690 this->write("\0");
1691#endif
Ethan Nicholascc305772017-10-13 16:17:45 -04001692 return true;
Ethan Nicholascc305772017-10-13 16:17:45 -04001693}
1694
1695}