blob: c555b8a33d8c7a4053c7e6a8999e9279a7428e4c [file] [log] [blame]
ethannicholasf789b382016-08-03 12:43:36 -07001/*
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 */
Greg Daniel64773e62016-11-22 09:44:03 -05007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLGLSLCodeGenerator.h"
ethannicholasf789b382016-08-03 12:43:36 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/SkSLCompiler.h"
11#include "src/sksl/ir/SkSLExpressionStatement.h"
12#include "src/sksl/ir/SkSLExtension.h"
13#include "src/sksl/ir/SkSLIndexExpression.h"
14#include "src/sksl/ir/SkSLModifiersDeclaration.h"
15#include "src/sksl/ir/SkSLNop.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasf789b382016-08-03 12:43:36 -070017
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040018#ifndef SKSL_STANDALONE
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/private/SkOnce.h"
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040020#endif
21
ethannicholasf789b382016-08-03 12:43:36 -070022namespace SkSL {
23
24void GLSLCodeGenerator::write(const char* s) {
25 if (s[0] == 0) {
26 return;
27 }
28 if (fAtLineStart) {
29 for (int i = 0; i < fIndentation; i++) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050030 fOut->writeText(" ");
ethannicholasf789b382016-08-03 12:43:36 -070031 }
32 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050033 fOut->writeText(s);
ethannicholasf789b382016-08-03 12:43:36 -070034 fAtLineStart = false;
35}
36
37void GLSLCodeGenerator::writeLine(const char* s) {
38 this->write(s);
Ethan Nicholas762466e2017-06-29 10:03:38 -040039 fOut->writeText(fLineEnding);
ethannicholasf789b382016-08-03 12:43:36 -070040 fAtLineStart = true;
41}
42
Ethan Nicholas0df1b042017-03-31 13:56:23 -040043void GLSLCodeGenerator::write(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070044 this->write(s.c_str());
45}
46
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070047void GLSLCodeGenerator::write(StringFragment s) {
48 if (!s.fLength) {
49 return;
50 }
51 if (fAtLineStart) {
52 for (int i = 0; i < fIndentation; i++) {
53 fOut->writeText(" ");
54 }
55 }
56 fOut->write(s.fChars, s.fLength);
57 fAtLineStart = false;
58}
59
Ethan Nicholas0df1b042017-03-31 13:56:23 -040060void GLSLCodeGenerator::writeLine(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070061 this->writeLine(s.c_str());
62}
63
64void GLSLCodeGenerator::writeLine() {
65 this->writeLine("");
66}
67
Ethan Nicholas88f6d372018-07-27 10:03:46 -040068void GLSLCodeGenerator::writeExtension(const String& name) {
69 this->writeExtension(name, true);
70}
71
72void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
73 fExtensions.writeText("#extension ");
74 fExtensions.write(name.c_str(), name.length());
75 fExtensions.writeText(require ? " : require\n" : " : enable\n");
ethannicholasf789b382016-08-03 12:43:36 -070076}
77
Ethan Nicholasf7b88202017-09-18 14:10:39 -040078bool GLSLCodeGenerator::usesPrecisionModifiers() const {
79 return fProgram.fSettings.fCaps->usesPrecisionModifiers();
80}
81
82String GLSLCodeGenerator::getTypeName(const Type& type) {
83 switch (type.kind()) {
84 case Type::kVector_Kind: {
85 Type component = type.componentType();
86 String result;
87 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
88 result = "vec";
89 }
90 else if (component == *fContext.fDouble_Type) {
91 result = "dvec";
92 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050093 else if (component.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040094 result = "ivec";
95 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050096 else if (component.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040097 result = "uvec";
98 }
99 else if (component == *fContext.fBool_Type) {
100 result = "bvec";
101 }
102 else {
103 ABORT("unsupported vector type");
104 }
105 result += to_string(type.columns());
106 return result;
107 }
108 case Type::kMatrix_Kind: {
109 String result;
110 Type component = type.componentType();
111 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
112 result = "mat";
113 }
114 else if (component == *fContext.fDouble_Type) {
115 result = "dmat";
116 }
117 else {
118 ABORT("unsupported matrix type");
119 }
120 result += to_string(type.columns());
121 if (type.columns() != type.rows()) {
122 result += "x";
123 result += to_string(type.rows());
124 }
125 return result;
126 }
127 case Type::kArray_Kind: {
128 String result = this->getTypeName(type.componentType()) + "[";
129 if (type.columns() != -1) {
130 result += to_string(type.columns());
131 }
132 result += "]";
133 return result;
134 }
135 case Type::kScalar_Kind: {
136 if (type == *fContext.fHalf_Type) {
137 return "float";
138 }
139 else if (type == *fContext.fShort_Type) {
140 return "int";
141 }
142 else if (type == *fContext.fUShort_Type) {
143 return "uint";
144 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400145 else if (type == *fContext.fByte_Type) {
146 return "int";
147 }
148 else if (type == *fContext.fUByte_Type) {
149 return "uint";
150 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400151 else {
152 return type.name();
153 }
154 break;
155 }
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500156 case Type::kEnum_Kind:
157 return "int";
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400158 default:
159 return type.name();
160 }
161}
162
ethannicholasf789b382016-08-03 12:43:36 -0700163void GLSLCodeGenerator::writeType(const Type& type) {
164 if (type.kind() == Type::kStruct_Kind) {
165 for (const Type* search : fWrittenStructs) {
166 if (*search == type) {
167 // already written
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700168 this->write(type.fName);
ethannicholasf789b382016-08-03 12:43:36 -0700169 return;
170 }
171 }
172 fWrittenStructs.push_back(&type);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700173 this->write("struct ");
174 this->write(type.fName);
175 this->writeLine(" {");
ethannicholasf789b382016-08-03 12:43:36 -0700176 fIndentation++;
177 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700178 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400179 this->writeTypePrecision(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700180 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -0700181 this->writeType(*f.fType);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700182 this->write(" ");
183 this->write(f.fName);
184 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -0700185 }
186 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -0500187 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -0700188 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400189 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700190 }
191}
192
193void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
194 switch (expr.fKind) {
195 case Expression::kBinary_Kind:
196 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
197 break;
198 case Expression::kBoolLiteral_Kind:
199 this->writeBoolLiteral((BoolLiteral&) expr);
200 break;
201 case Expression::kConstructor_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400202 this->writeConstructor((Constructor&) expr, parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700203 break;
204 case Expression::kIntLiteral_Kind:
205 this->writeIntLiteral((IntLiteral&) expr);
206 break;
207 case Expression::kFieldAccess_Kind:
208 this->writeFieldAccess(((FieldAccess&) expr));
209 break;
210 case Expression::kFloatLiteral_Kind:
211 this->writeFloatLiteral(((FloatLiteral&) expr));
212 break;
213 case Expression::kFunctionCall_Kind:
214 this->writeFunctionCall((FunctionCall&) expr);
215 break;
216 case Expression::kPrefix_Kind:
217 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
218 break;
219 case Expression::kPostfix_Kind:
220 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
221 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400222 case Expression::kSetting_Kind:
223 this->writeSetting((Setting&) expr);
224 break;
ethannicholasf789b382016-08-03 12:43:36 -0700225 case Expression::kSwizzle_Kind:
226 this->writeSwizzle((Swizzle&) expr);
227 break;
228 case Expression::kVariableReference_Kind:
229 this->writeVariableReference((VariableReference&) expr);
230 break;
231 case Expression::kTernary_Kind:
232 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
233 break;
234 case Expression::kIndex_Kind:
235 this->writeIndexExpression((IndexExpression&) expr);
236 break;
237 default:
238 ABORT("unsupported expression: %s", expr.description().c_str());
239 }
240}
241
ethannicholas5961bc92016-10-12 06:39:56 -0700242static bool is_abs(Expression& expr) {
243 if (expr.fKind != Expression::kFunctionCall_Kind) {
244 return false;
245 }
246 return ((FunctionCall&) expr).fFunction.fName == "abs";
247}
248
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500249// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700250// Tegra3 compiler bug.
251void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400252 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400253 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
254 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400255 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.fType) +
256 this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
257 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.fType) +
258 this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700259 this->write("((" + tmpVar1 + " = ");
260 this->writeExpression(absExpr, kTopLevel_Precedence);
261 this->write(") < (" + tmpVar2 + " = ");
262 this->writeExpression(otherExpr, kAssignment_Precedence);
263 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
264}
265
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500266void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
267 this->write("(1.0 / sqrt(");
268 this->writeExpression(x, kTopLevel_Precedence);
269 this->write("))");
270}
271
272void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
273 String name;
274 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
275 name = "_determinant2";
276 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
277 fWrittenIntrinsics.insert(name);
278 fExtraFunctions.writeText((
279 "float " + name + "(mat2 m) {"
280 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
281 "}"
282 ).c_str());
283 }
284 }
285 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
286 name = "_determinant3";
287 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
288 fWrittenIntrinsics.insert(name);
289 fExtraFunctions.writeText((
290 "float " + name + "(mat3 m) {"
291 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
292 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
293 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
294 " float b01 = a22 * a11 - a12 * a21;"
295 " float b11 = -a22 * a10 + a12 * a20;"
296 " float b21 = a21 * a10 - a11 * a20;"
297 " return a00 * b01 + a01 * b11 + a02 * b21;"
298 "}"
299 ).c_str());
300 }
301 }
302 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
303 name = "_determinant3";
304 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
305 fWrittenIntrinsics.insert(name);
306 fExtraFunctions.writeText((
307 "mat4 " + name + "(mat4 m) {"
308 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
309 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
310 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
311 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
312 " float b00 = a00 * a11 - a01 * a10;"
313 " float b01 = a00 * a12 - a02 * a10;"
314 " float b02 = a00 * a13 - a03 * a10;"
315 " float b03 = a01 * a12 - a02 * a11;"
316 " float b04 = a01 * a13 - a03 * a11;"
317 " float b05 = a02 * a13 - a03 * a12;"
318 " float b06 = a20 * a31 - a21 * a30;"
319 " float b07 = a20 * a32 - a22 * a30;"
320 " float b08 = a20 * a33 - a23 * a30;"
321 " float b09 = a21 * a32 - a22 * a31;"
322 " float b10 = a21 * a33 - a23 * a31;"
323 " float b11 = a22 * a33 - a23 * a32;"
324 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
325 "}"
326 ).c_str());
327 }
328 }
329 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400330 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500331 }
332 this->write(name + "(");
333 this->writeExpression(mat, kTopLevel_Precedence);
334 this->write(")");
335}
336
337void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
338 String name;
339 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
340 name = "_inverse2";
341 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
342 fWrittenIntrinsics.insert(name);
343 fExtraFunctions.writeText((
344 "mat2 " + name + "(mat2 m) {"
345 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
346 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
347 "}"
348 ).c_str());
349 }
350 }
351 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
352 name = "_inverse3";
353 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
354 fWrittenIntrinsics.insert(name);
355 fExtraFunctions.writeText((
356 "mat3 " + name + "(mat3 m) {"
357 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
358 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
359 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
360 " float b01 = a22 * a11 - a12 * a21;"
361 " float b11 = -a22 * a10 + a12 * a20;"
362 " float b21 = a21 * a10 - a11 * a20;"
363 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
364 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
365 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
366 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
367 "}"
368 ).c_str());
369 }
370 }
371 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
372 name = "_inverse4";
373 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
374 fWrittenIntrinsics.insert(name);
375 fExtraFunctions.writeText((
376 "mat4 " + name + "(mat4 m) {"
377 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
378 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
379 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
380 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
381 " float b00 = a00 * a11 - a01 * a10;"
382 " float b01 = a00 * a12 - a02 * a10;"
383 " float b02 = a00 * a13 - a03 * a10;"
384 " float b03 = a01 * a12 - a02 * a11;"
385 " float b04 = a01 * a13 - a03 * a11;"
386 " float b05 = a02 * a13 - a03 * a12;"
387 " float b06 = a20 * a31 - a21 * a30;"
388 " float b07 = a20 * a32 - a22 * a30;"
389 " float b08 = a20 * a33 - a23 * a30;"
390 " float b09 = a21 * a32 - a22 * a31;"
391 " float b10 = a21 * a33 - a23 * a31;"
392 " float b11 = a22 * a33 - a23 * a32;"
393 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
394 " b04 * b07 + b05 * b06;"
395 " return mat4("
396 " a11 * b11 - a12 * b10 + a13 * b09,"
397 " a02 * b10 - a01 * b11 - a03 * b09,"
398 " a31 * b05 - a32 * b04 + a33 * b03,"
399 " a22 * b04 - a21 * b05 - a23 * b03,"
400 " a12 * b08 - a10 * b11 - a13 * b07,"
401 " a00 * b11 - a02 * b08 + a03 * b07,"
402 " a32 * b02 - a30 * b05 - a33 * b01,"
403 " a20 * b05 - a22 * b02 + a23 * b01,"
404 " a10 * b10 - a11 * b08 + a13 * b06,"
405 " a01 * b08 - a00 * b10 - a03 * b06,"
406 " a30 * b04 - a31 * b02 + a33 * b00,"
407 " a21 * b02 - a20 * b04 - a23 * b00,"
408 " a11 * b07 - a10 * b09 - a12 * b06,"
409 " a00 * b09 - a01 * b07 + a02 * b06,"
410 " a31 * b01 - a30 * b03 - a32 * b00,"
411 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
412 "}"
413 ).c_str());
414 }
415 }
416 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400417 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500418 }
419 this->write(name + "(");
420 this->writeExpression(mat, kTopLevel_Precedence);
421 this->write(")");
422}
423
424void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
425 String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
426 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
427 fWrittenIntrinsics.insert(name);
428 String type = this->getTypeName(mat.fType);
429 const Type& base = mat.fType.componentType();
430 String transposed = this->getTypeName(base.toCompound(fContext,
431 mat.fType.rows(),
432 mat.fType.columns()));
433 fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
434 transposed + "(").c_str());
435 const char* separator = "";
436 for (int row = 0; row < mat.fType.rows(); ++row) {
437 for (int column = 0; column < mat.fType.columns(); ++column) {
438 fExtraFunctions.writeText(separator);
439 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
440 "]").c_str());
441 separator = ", ";
442 }
443 }
444 fExtraFunctions.writeText("); }");
445 }
446 this->write(name + "(");
447 this->writeExpression(mat, kTopLevel_Precedence);
448 this->write(")");
449}
450
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400451std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
452 GLSLCodeGenerator::fFunctionClasses = nullptr;
453
ethannicholasf789b382016-08-03 12:43:36 -0700454void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400455#ifdef SKSL_STANDALONE
456 if (!fFunctionClasses) {
457#else
458 static SkOnce once;
459 once([] {
460#endif
461 fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
Adrienne Walker92b161f2018-08-22 10:41:52 -0700462 (*fFunctionClasses)["abs"] = FunctionClass::kAbs;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400463 (*fFunctionClasses)["atan"] = FunctionClass::kAtan;
464 (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700465 (*fFunctionClasses)["dFdx"] = FunctionClass::kDFdx;
466 (*fFunctionClasses)["dFdy"] = FunctionClass::kDFdy;
467 (*fFunctionClasses)["fwidth"] = FunctionClass::kFwidth;
Chris Daltona7086182018-11-16 09:33:43 -0500468 (*fFunctionClasses)["fma"] = FunctionClass::kFMA;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400469 (*fFunctionClasses)["fract"] = FunctionClass::kFract;
470 (*fFunctionClasses)["inverse"] = FunctionClass::kInverse;
471 (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
472 (*fFunctionClasses)["min"] = FunctionClass::kMin;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700473 (*fFunctionClasses)["pow"] = FunctionClass::kPow;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400474 (*fFunctionClasses)["saturate"] = FunctionClass::kSaturate;
Ethan Nicholas13863662019-07-29 13:05:15 -0400475 (*fFunctionClasses)["sample"] = FunctionClass::kTexture;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400476 (*fFunctionClasses)["transpose"] = FunctionClass::kTranspose;
ethannicholas5961bc92016-10-12 06:39:56 -0700477 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400478#ifndef SKSL_STANDALONE
479 );
480#endif
481 const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
482 fFunctionClasses->end();
Brian Osman8a83ca42018-02-12 14:32:17 -0500483 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400484 bool nameWritten = false;
485 if (found != fFunctionClasses->end()) {
486 switch (found->second) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700487 case FunctionClass::kAbs: {
488 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
489 break;
490 SkASSERT(c.fArguments.size() == 1);
491 if (c.fArguments[0]->fType != *fContext.fInt_Type)
492 break;
493 // abs(int) on Intel OSX is incorrect, so emulate it:
494 String name = "_absemulation";
495 this->write(name);
496 nameWritten = true;
497 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
498 fWrittenIntrinsics.insert(name);
499 fExtraFunctions.writeText((
500 "int " + name + "(int x) {\n"
501 " return x * sign(x);\n"
502 "}\n"
503 ).c_str());
504 }
505 break;
506 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400507 case FunctionClass::kAtan:
508 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
509 c.fArguments.size() == 2 &&
510 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
511 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
512 if (p.fOperator == Token::MINUS) {
513 this->write("atan(");
514 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
515 this->write(", -1.0 * ");
516 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
517 this->write(")");
518 return;
519 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500520 }
521 break;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700522 case FunctionClass::kDFdy:
523 if (fProgram.fSettings.fFlipY) {
524 // Flipping Y also negates the Y derivatives.
525 this->write("-dFdy");
526 nameWritten = true;
527 }
528 // fallthru
529 case FunctionClass::kDFdx:
530 case FunctionClass::kFwidth:
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400531 if (!fFoundDerivatives &&
532 fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
533 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
534 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
535 fFoundDerivatives = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500536 }
537 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400538 case FunctionClass::kDeterminant:
539 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
540 SkASSERT(c.fArguments.size() == 1);
541 this->writeDeterminantHack(*c.fArguments[0]);
542 return;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500543 }
544 break;
Chris Daltona7086182018-11-16 09:33:43 -0500545 case FunctionClass::kFMA:
546 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
547 SkASSERT(c.fArguments.size() == 3);
548 this->write("((");
549 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
550 this->write(") * (");
551 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
552 this->write(") + (");
553 this->writeExpression(*c.fArguments[2], kSequence_Precedence);
554 this->write("))");
555 return;
556 }
557 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400558 case FunctionClass::kFract:
559 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
560 SkASSERT(c.fArguments.size() == 1);
561 this->write("(0.5 - sign(");
562 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
563 this->write(") * (0.5 - fract(abs(");
564 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
565 this->write("))))");
566 return;
567 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500568 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400569 case FunctionClass::kInverse:
570 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
571 SkASSERT(c.fArguments.size() == 1);
572 this->writeInverseHack(*c.fArguments[0]);
573 return;
574 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500575 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400576 case FunctionClass::kInverseSqrt:
577 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
578 SkASSERT(c.fArguments.size() == 1);
579 this->writeInverseSqrtHack(*c.fArguments[0]);
580 return;
581 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500582 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400583 case FunctionClass::kMin:
584 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
585 SkASSERT(c.fArguments.size() == 2);
586 if (is_abs(*c.fArguments[0])) {
587 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
588 return;
589 }
590 if (is_abs(*c.fArguments[1])) {
591 // note that this violates the GLSL left-to-right evaluation semantics.
592 // I doubt it will ever end up mattering, but it's worth calling out.
593 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
594 return;
595 }
596 }
597 break;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700598 case FunctionClass::kPow:
599 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
600 break;
601 }
602 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
603 // constant. It's hard to tell what constitutes "constant" here
604 // so just replace in all cases.
605
606 // Change pow(x, y) into exp2(y * log2(x))
607 this->write("exp2(");
608 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
609 this->write(" * log2(");
610 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
611 this->write("))");
612 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400613 case FunctionClass::kSaturate:
614 SkASSERT(c.fArguments.size() == 1);
615 this->write("clamp(");
616 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
617 this->write(", 0.0, 1.0)");
618 return;
619 case FunctionClass::kTexture: {
620 const char* dim = "";
621 bool proj = false;
622 switch (c.fArguments[0]->fType.dimensions()) {
623 case SpvDim1D:
624 dim = "1D";
625 isTextureFunctionWithBias = true;
626 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
627 proj = false;
628 } else {
629 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
630 proj = true;
631 }
632 break;
633 case SpvDim2D:
634 dim = "2D";
635 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
636 isTextureFunctionWithBias = true;
637 }
638 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
639 proj = false;
640 } else {
641 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
642 proj = true;
643 }
644 break;
645 case SpvDim3D:
646 dim = "3D";
647 isTextureFunctionWithBias = true;
648 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
649 proj = false;
650 } else {
651 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
652 proj = true;
653 }
654 break;
655 case SpvDimCube:
656 dim = "Cube";
657 isTextureFunctionWithBias = true;
658 proj = false;
659 break;
660 case SpvDimRect:
Khushal Sagar2cb13152019-09-11 23:17:26 +0000661 dim = "2DRect";
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400662 proj = false;
663 break;
664 case SpvDimBuffer:
665 SkASSERT(false); // doesn't exist
666 dim = "Buffer";
667 proj = false;
668 break;
669 case SpvDimSubpassData:
670 SkASSERT(false); // doesn't exist
671 dim = "SubpassData";
672 proj = false;
673 break;
674 }
Ethan Nicholas13863662019-07-29 13:05:15 -0400675 if (fTextureFunctionOverride != "") {
676 this->write(fTextureFunctionOverride.c_str());
677 } else {
678 this->write("texture");
679 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
680 this->write(dim);
681 }
682 if (proj) {
683 this->write("Proj");
684 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400685 }
686 nameWritten = true;
687 break;
688 }
689 case FunctionClass::kTranspose:
690 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
691 SkASSERT(c.fArguments.size() == 1);
692 this->writeTransposeHack(*c.fArguments[0]);
693 return;
694 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500695 break;
696 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400697 }
698 if (!nameWritten) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500699 this->write(c.fFunction.fName);
700 }
701 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700702 const char* separator = "";
703 for (const auto& arg : c.fArguments) {
704 this->write(separator);
705 separator = ", ";
706 this->writeExpression(*arg, kSequence_Precedence);
707 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500708 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
709 this->write(", -0.5");
710 }
ethannicholasf789b382016-08-03 12:43:36 -0700711 this->write(")");
712}
713
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400714void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
715 if (c.fArguments.size() == 1 &&
Ethan Nicholase1f55022019-02-05 17:17:40 -0500716 (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
717 (c.fType.kind() == Type::kScalar_Kind &&
718 c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400719 // in cases like half(float), they're different types as far as SkSL is concerned but the
720 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
721 // out the inner expression here.
722 this->writeExpression(*c.fArguments[0], parentPrecedence);
723 return;
724 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400725 this->writeType(c.fType);
726 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700727 const char* separator = "";
728 for (const auto& arg : c.fArguments) {
729 this->write(separator);
730 separator = ", ";
731 this->writeExpression(*arg, kSequence_Precedence);
732 }
733 this->write(")");
734}
735
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500736void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000737 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500738 if (!fSetupFragCoordWorkaround) {
739 const char* precision = usesPrecisionModifiers() ? "highp " : "";
740 fFunctionHeader += precision;
741 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
742 fFunctionHeader += precision;
743 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
744 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
745 // Ensure that we get exact .5 values for x and y.
746 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
747 "vec2(.5);\n";
748 fSetupFragCoordWorkaround = true;
749 }
750 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000751 return;
752 }
753
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500754 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
755 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
756 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
757 if (!fProgram.fSettings.fFlipY) {
758 this->write("gl_FragCoord");
759 } else if (const char* extension =
Ethan Nicholascd700e92018-08-24 16:43:57 -0400760 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500761 if (!fSetupFragPositionGlobal) {
762 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400763 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500764 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400765 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500766 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000767 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500768 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000769 } else {
Ethan Nicholascd700e92018-08-24 16:43:57 -0400770 if (!fSetupFragPositionLocal) {
Michael Ludwig5e1f6ea2018-12-03 15:14:50 -0500771 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
Michael Ludwigf0b60442018-12-10 14:43:38 +0000772 fFunctionHeader += " vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
773 " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500774 fSetupFragPositionLocal = true;
775 }
776 this->write("sk_FragCoord");
777 }
778}
779
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500780void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
781 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
782 case SK_FRAGCOLOR_BUILTIN:
783 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
784 this->write("sk_FragColor");
785 } else {
786 this->write("gl_FragColor");
787 }
788 break;
789 case SK_FRAGCOORD_BUILTIN:
790 this->writeFragCoord();
791 break;
Ethan Nicholascd700e92018-08-24 16:43:57 -0400792 case SK_WIDTH_BUILTIN:
793 this->write("u_skRTWidth");
794 break;
795 case SK_HEIGHT_BUILTIN:
796 this->write("u_skRTHeight");
797 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600798 case SK_CLOCKWISE_BUILTIN:
Chris Daltonc8ece3d2018-07-30 15:03:45 -0600799 this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
Chris Dalton49d14e92018-07-27 12:38:35 -0600800 break;
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600801 case SK_SAMPLEMASK_BUILTIN:
Chris Dalton8a64a442019-10-29 18:54:58 -0600802 SkASSERT(fProgram.fSettings.fCaps->sampleMaskSupport());
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600803 this->write("gl_SampleMask");
804 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500805 case SK_VERTEXID_BUILTIN:
806 this->write("gl_VertexID");
807 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600808 case SK_INSTANCEID_BUILTIN:
809 this->write("gl_InstanceID");
810 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500811 case SK_CLIPDISTANCE_BUILTIN:
812 this->write("gl_ClipDistance");
813 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500814 case SK_IN_BUILTIN:
815 this->write("gl_in");
816 break;
817 case SK_INVOCATIONID_BUILTIN:
818 this->write("gl_InvocationID");
819 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400820 case SK_LASTFRAGCOLOR_BUILTIN:
821 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
822 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500823 default:
824 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700825 }
ethannicholasf789b382016-08-03 12:43:36 -0700826}
827
828void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
829 this->writeExpression(*expr.fBase, kPostfix_Precedence);
830 this->write("[");
831 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
832 this->write("]");
833}
834
Brian Osmancd3261a2018-01-16 13:52:29 +0000835bool is_sk_position(const FieldAccess& f) {
836 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
837}
838
ethannicholasf789b382016-08-03 12:43:36 -0700839void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
840 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
841 this->writeExpression(*f.fBase, kPostfix_Precedence);
842 this->write(".");
843 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500844 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
845 case SK_CLIPDISTANCE_BUILTIN:
846 this->write("gl_ClipDistance");
847 break;
848 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400849 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
850 if (name == "sk_Position") {
851 this->write("gl_Position");
852 } else if (name == "sk_PointSize") {
853 this->write("gl_PointSize");
854 } else {
855 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
856 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500857 }
ethannicholasf789b382016-08-03 12:43:36 -0700858}
859
Ethan Nicholase455f652019-09-13 12:52:55 -0400860void GLSLCodeGenerator::writeConstantSwizzle(const Swizzle& swizzle, const String& constants) {
861 this->writeType(swizzle.fType);
862 this->write("(");
863 this->write(constants);
864 this->write(")");
865}
866
867void GLSLCodeGenerator::writeSwizzleMask(const Swizzle& swizzle, const String& mask) {
ethannicholasf789b382016-08-03 12:43:36 -0700868 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
869 this->write(".");
Ethan Nicholase455f652019-09-13 12:52:55 -0400870 this->write(mask);
871}
872
873void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
874 const String& mask,
875 GLSLCodeGenerator::SwizzleOrder order) {
876 this->writeType(swizzle.fType);
877 this->write("(");
878 if (order == SwizzleOrder::CONSTANTS_FIRST) {
879 this->write(constants);
880 this->write(", ");
881 this->writeSwizzleMask(swizzle, mask);
882 } else {
883 this->writeSwizzleMask(swizzle, mask);
884 this->write(", ");
885 this->write(constants);
886 }
887 this->write(")");
888}
889
890void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
891 const String& mask, const String& reswizzle) {
892 this->writeSwizzleConstructor(swizzle, constants, mask, SwizzleOrder::MASK_FIRST);
893 this->write(".");
894 this->write(reswizzle);
895}
896
897// Writing a swizzle is complicated due to the handling of constant swizzle components. The most
898// problematic case is a mask like '.r00a'. A naive approach might turn that into
899// 'vec4(base.r, 0, 0, base.a)', but that would cause 'base' to be evaluated twice. We instead
900// group the swizzle mask ('ra') and constants ('0, 0') together and use a secondary swizzle to put
901// them back into the right order, so in this case we end up with something like
902// 'vec4(base4.ra, 0, 0).rbag'.
903void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
904 // has a 1 bit in every position for which the swizzle mask is a constant, so 'r0b1' would
905 // yield binary 0101.
906 int constantBits = 0;
907 String mask;
908 String constants;
909 // compute mask ("ra") and constant ("0, 0") strings, and fill in constantBits
ethannicholasf789b382016-08-03 12:43:36 -0700910 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -0400911 constantBits <<= 1;
912 switch (c) {
913 case SKSL_SWIZZLE_0:
914 constantBits |= 1;
915 if (constants.length() > 0) {
916 constants += ", ";
917 }
918 constants += "0";
919 break;
920 case SKSL_SWIZZLE_1:
921 constantBits |= 1;
922 if (constants.length() > 0) {
923 constants += ", ";
924 }
925 constants += "1";
926 break;
927 case 0:
928 mask += "x";
929 break;
930 case 1:
931 mask += "y";
932 break;
933 case 2:
934 mask += "z";
935 break;
936 case 3:
937 mask += "w";
938 break;
939 default:
940 SkASSERT(false);
Ethan Nicholasac285b12019-02-12 16:05:18 -0500941 }
942 }
Ethan Nicholase455f652019-09-13 12:52:55 -0400943 switch (swizzle.fComponents.size()) {
944 case 1:
945 if (constantBits == 1) {
946 this->write(constants);
947 }
948 else {
949 this->writeSwizzleMask(swizzle, mask);
950 }
951 break;
952 case 2:
953 switch (constantBits) {
954 case 0: // 00
955 this->writeSwizzleMask(swizzle, mask);
956 break;
957 case 1: // 01
958 this->writeSwizzleConstructor(swizzle, constants, mask,
959 SwizzleOrder::MASK_FIRST);
960 break;
961 case 2: // 10
962 this->writeSwizzleConstructor(swizzle, constants, mask,
963 SwizzleOrder::CONSTANTS_FIRST);
964 break;
965 case 3: // 11
966 this->writeConstantSwizzle(swizzle, constants);
967 break;
968 default:
969 SkASSERT(false);
970 }
971 break;
972 case 3:
973 switch (constantBits) {
974 case 0: // 000
975 this->writeSwizzleMask(swizzle, mask);
976 break;
977 case 1: // 001
978 case 3: // 011
979 this->writeSwizzleConstructor(swizzle, constants, mask,
980 SwizzleOrder::MASK_FIRST);
981 break;
982 case 4: // 100
983 case 6: // 110
984 this->writeSwizzleConstructor(swizzle, constants, mask,
985 SwizzleOrder::CONSTANTS_FIRST);
986 break;
987 case 2: // 010
988 this->writeSwizzleConstructor(swizzle, constants, mask, "xzy");
989 break;
990 case 5: // 101
991 this->writeSwizzleConstructor(swizzle, constants, mask, "yxz");
992 break;
993 case 7: // 111
994 this->writeConstantSwizzle(swizzle, constants);
995 break;
996 }
997 break;
998 case 4:
999 switch (constantBits) {
1000 case 0: // 0000
1001 this->writeSwizzleMask(swizzle, mask);
1002 break;
1003 case 1: // 0001
1004 case 3: // 0011
1005 case 7: // 0111
1006 this->writeSwizzleConstructor(swizzle, constants, mask,
1007 SwizzleOrder::MASK_FIRST);
1008 break;
1009 case 8: // 1000
1010 case 12: // 1100
1011 case 14: // 1110
1012 this->writeSwizzleConstructor(swizzle, constants, mask,
1013 SwizzleOrder::CONSTANTS_FIRST);
1014 break;
1015 case 2: // 0010
1016 this->writeSwizzleConstructor(swizzle, constants, mask, "xywz");
1017 break;
1018 case 4: // 0100
1019 this->writeSwizzleConstructor(swizzle, constants, mask, "xwyz");
1020 break;
1021 case 5: // 0101
1022 this->writeSwizzleConstructor(swizzle, constants, mask, "xzyw");
1023 break;
1024 case 6: // 0110
1025 this->writeSwizzleConstructor(swizzle, constants, mask, "xzwy");
1026 break;
1027 case 9: // 1001
1028 this->writeSwizzleConstructor(swizzle, constants, mask, "zxyw");
1029 break;
1030 case 10: // 1010
1031 this->writeSwizzleConstructor(swizzle, constants, mask, "zxwy");
1032 break;
1033 case 11: // 1011
1034 this->writeSwizzleConstructor(swizzle, constants, mask, "yxzw");
1035 break;
1036 case 13: // 1101
1037 this->writeSwizzleConstructor(swizzle, constants, mask, "yzxw");
1038 break;
1039 case 15: // 1111
1040 this->writeConstantSwizzle(swizzle, constants);
1041 break;
1042 }
ethannicholasf789b382016-08-03 12:43:36 -07001043 }
1044}
1045
Ethan Nicholas762466e2017-06-29 10:03:38 -04001046GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -07001047 switch (op) {
1048 case Token::STAR: // fall through
1049 case Token::SLASH: // fall through
1050 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
1051 case Token::PLUS: // fall through
1052 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
1053 case Token::SHL: // fall through
1054 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
1055 case Token::LT: // fall through
1056 case Token::GT: // fall through
1057 case Token::LTEQ: // fall through
1058 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
1059 case Token::EQEQ: // fall through
1060 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
1061 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
1062 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
1063 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
1064 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
1065 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
1066 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
1067 case Token::EQ: // fall through
1068 case Token::PLUSEQ: // fall through
1069 case Token::MINUSEQ: // fall through
1070 case Token::STAREQ: // fall through
1071 case Token::SLASHEQ: // fall through
1072 case Token::PERCENTEQ: // fall through
1073 case Token::SHLEQ: // fall through
1074 case Token::SHREQ: // fall through
1075 case Token::LOGICALANDEQ: // fall through
1076 case Token::LOGICALXOREQ: // fall through
1077 case Token::LOGICALOREQ: // fall through
1078 case Token::BITWISEANDEQ: // fall through
1079 case Token::BITWISEXOREQ: // fall through
1080 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001081 case Token::COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -07001082 default: ABORT("unsupported binary operator");
1083 }
1084}
1085
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001086void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -07001087 Precedence parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001088 if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
1089 (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
1090 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
1091 return;
1092 }
1093
Ethan Nicholas762466e2017-06-29 10:03:38 -04001094 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -07001095 if (precedence >= parentPrecedence) {
1096 this->write("(");
1097 }
Ethan Nicholas0b631962018-07-24 13:41:11 -04001098 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
1099 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +00001100 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
1101 is_sk_position((FieldAccess&) *b.fLeft) &&
1102 !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
1103 !fProgram.fSettings.fCaps->canUseFragCoord();
1104 if (positionWorkaround) {
1105 this->write("sk_FragCoord_Workaround = (");
1106 }
ethannicholasf789b382016-08-03 12:43:36 -07001107 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001108 this->write(" ");
1109 this->write(Compiler::OperatorName(b.fOperator));
1110 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -07001111 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +00001112 if (positionWorkaround) {
1113 this->write(")");
1114 }
ethannicholasf789b382016-08-03 12:43:36 -07001115 if (precedence >= parentPrecedence) {
1116 this->write(")");
1117 }
1118}
1119
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001120void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
1121 Precedence parentPrecedence) {
1122 if (kTernary_Precedence >= parentPrecedence) {
1123 this->write("(");
1124 }
1125
1126 // Transform:
1127 // a && b => a ? b : false
1128 // a || b => a ? true : b
1129 this->writeExpression(*b.fLeft, kTernary_Precedence);
1130 this->write(" ? ");
1131 if (b.fOperator == Token::LOGICALAND) {
1132 this->writeExpression(*b.fRight, kTernary_Precedence);
1133 } else {
1134 BoolLiteral boolTrue(fContext, -1, true);
1135 this->writeBoolLiteral(boolTrue);
1136 }
1137 this->write(" : ");
1138 if (b.fOperator == Token::LOGICALAND) {
1139 BoolLiteral boolFalse(fContext, -1, false);
1140 this->writeBoolLiteral(boolFalse);
1141 } else {
1142 this->writeExpression(*b.fRight, kTernary_Precedence);
1143 }
1144 if (kTernary_Precedence >= parentPrecedence) {
1145 this->write(")");
1146 }
1147}
1148
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001149void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -07001150 Precedence parentPrecedence) {
1151 if (kTernary_Precedence >= parentPrecedence) {
1152 this->write("(");
1153 }
1154 this->writeExpression(*t.fTest, kTernary_Precedence);
1155 this->write(" ? ");
1156 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
1157 this->write(" : ");
1158 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
1159 if (kTernary_Precedence >= parentPrecedence) {
1160 this->write(")");
1161 }
1162}
1163
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001164void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001165 Precedence parentPrecedence) {
1166 if (kPrefix_Precedence >= parentPrecedence) {
1167 this->write("(");
1168 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001169 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001170 this->writeExpression(*p.fOperand, kPrefix_Precedence);
1171 if (kPrefix_Precedence >= parentPrecedence) {
1172 this->write(")");
1173 }
1174}
1175
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001176void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001177 Precedence parentPrecedence) {
1178 if (kPostfix_Precedence >= parentPrecedence) {
1179 this->write("(");
1180 }
1181 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001182 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001183 if (kPostfix_Precedence >= parentPrecedence) {
1184 this->write(")");
1185 }
1186}
1187
1188void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1189 this->write(b.fValue ? "true" : "false");
1190}
1191
1192void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -07001193 if (i.fType == *fContext.fUInt_Type) {
1194 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -05001195 } else if (i.fType == *fContext.fUShort_Type) {
1196 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001197 } else if (i.fType == *fContext.fUByte_Type) {
1198 this->write(to_string(i.fValue & 0xff) + "u");
1199 } else {
ethannicholas5961bc92016-10-12 06:39:56 -07001200 this->write(to_string((int32_t) i.fValue));
1201 }
ethannicholasf789b382016-08-03 12:43:36 -07001202}
1203
1204void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1205 this->write(to_string(f.fValue));
1206}
1207
Ethan Nicholas762466e2017-06-29 10:03:38 -04001208void GLSLCodeGenerator::writeSetting(const Setting& s) {
1209 ABORT("internal error; setting was not folded to a constant during compilation\n");
1210}
1211
ethannicholasf789b382016-08-03 12:43:36 -07001212void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholasc6dce5a2019-07-24 16:51:36 -04001213 fSetupFragPositionLocal = false;
1214 fSetupFragCoordWorkaround = false;
Ethan Nicholas00543112018-07-31 09:44:36 -04001215 if (fProgramKind != Program::kPipelineStage_Kind) {
1216 this->writeTypePrecision(f.fDeclaration.fReturnType);
1217 this->writeType(f.fDeclaration.fReturnType);
1218 this->write(" " + f.fDeclaration.fName + "(");
1219 const char* separator = "";
1220 for (const auto& param : f.fDeclaration.fParameters) {
1221 this->write(separator);
1222 separator = ", ";
1223 this->writeModifiers(param->fModifiers, false);
1224 std::vector<int> sizes;
1225 const Type* type = &param->fType;
1226 while (type->kind() == Type::kArray_Kind) {
1227 sizes.push_back(type->columns());
1228 type = &type->componentType();
1229 }
1230 this->writeTypePrecision(*type);
1231 this->writeType(*type);
1232 this->write(" " + param->fName);
1233 for (int s : sizes) {
1234 if (s <= 0) {
1235 this->write("[]");
1236 } else {
1237 this->write("[" + to_string(s) + "]");
1238 }
ethannicholas5961bc92016-10-12 06:39:56 -07001239 }
1240 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001241 this->writeLine(") {");
1242 fIndentation++;
ethannicholasf789b382016-08-03 12:43:36 -07001243 }
ethannicholas5961bc92016-10-12 06:39:56 -07001244 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001245 OutputStream* oldOut = fOut;
1246 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001247 fOut = &buffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04001248 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas00543112018-07-31 09:44:36 -04001249 if (fProgramKind != Program::kPipelineStage_Kind) {
1250 fIndentation--;
1251 this->writeLine("}");
1252 }
ethannicholas5961bc92016-10-12 06:39:56 -07001253
1254 fOut = oldOut;
1255 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001256 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001257}
1258
Greg Daniel64773e62016-11-22 09:44:03 -05001259void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001260 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001261 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1262 this->write("flat ");
1263 }
ethannicholas5961bc92016-10-12 06:39:56 -07001264 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1265 this->write("noperspective ");
1266 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001267 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001268 if (layout.size()) {
1269 this->write(layout + " ");
1270 }
Brian Salomonf9f45122016-11-29 11:59:17 -05001271 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1272 this->write("readonly ");
1273 }
1274 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1275 this->write("writeonly ");
1276 }
1277 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1278 this->write("coherent ");
1279 }
1280 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1281 this->write("volatile ");
1282 }
1283 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1284 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -07001285 }
Greg Daniel64773e62016-11-22 09:44:03 -05001286 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001287 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1288 this->write("inout ");
1289 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001290 if (globalContext &&
1291 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001292 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1293 : "varying ");
1294 } else {
1295 this->write("in ");
1296 }
1297 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001298 if (globalContext &&
1299 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001300 this->write("varying ");
1301 } else {
1302 this->write("out ");
1303 }
1304 }
1305 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1306 this->write("uniform ");
1307 }
1308 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1309 this->write("const ");
1310 }
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001311 if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1312 this->write("__pixel_localEXT ");
1313 }
1314 if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1315 this->write("__pixel_local_inEXT ");
1316 }
1317 if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1318 this->write("__pixel_local_outEXT ");
1319 }
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001320 switch (modifiers.fLayout.fFormat) {
1321 case Layout::Format::kUnspecified:
1322 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001323 case Layout::Format::kRGBA32F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001324 case Layout::Format::kR32F:
ethannicholas5961bc92016-10-12 06:39:56 -07001325 this->write("highp ");
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001326 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001327 case Layout::Format::kRGBA16F: // fall through
1328 case Layout::Format::kR16F: // fall through
1329 case Layout::Format::kLUMINANCE16F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001330 case Layout::Format::kRG16F:
1331 this->write("mediump ");
1332 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001333 case Layout::Format::kRGBA8: // fall through
1334 case Layout::Format::kR8: // fall through
1335 case Layout::Format::kRGBA8I: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001336 case Layout::Format::kR8I:
1337 this->write("lowp ");
1338 break;
ethannicholas5961bc92016-10-12 06:39:56 -07001339 }
ethannicholasf789b382016-08-03 12:43:36 -07001340}
1341
1342void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001343 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001344 return;
1345 }
ethannicholas5961bc92016-10-12 06:39:56 -07001346 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001347 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001348 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001349 const Type* structType = &intf.fVariable.fType;
1350 while (structType->kind() == Type::kArray_Kind) {
1351 structType = &structType->componentType();
1352 }
1353 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001354 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001355 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001356 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001357 this->writeLine(" " + f.fName + ";");
1358 }
1359 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001360 this->write("}");
1361 if (intf.fInstanceName.size()) {
1362 this->write(" ");
1363 this->write(intf.fInstanceName);
1364 for (const auto& size : intf.fSizes) {
1365 this->write("[");
1366 if (size) {
1367 this->writeExpression(*size, kTopLevel_Precedence);
1368 }
1369 this->write("]");
1370 }
1371 }
1372 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001373}
1374
Ethan Nicholas762466e2017-06-29 10:03:38 -04001375void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1376 this->writeExpression(value, kTopLevel_Precedence);
1377}
1378
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001379const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1380 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001381 switch (type.kind()) {
1382 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001383 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1384 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001385 if (fProgram.fSettings.fForceHighPrecision ||
1386 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1387 return "highp ";
1388 }
1389 return "mediump ";
1390 }
1391 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001392 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001393 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001394 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1395 type == *fContext.fUInt_Type) {
1396 return "highp ";
1397 }
1398 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001399 case Type::kVector_Kind: // fall through
1400 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001401 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001402 default:
1403 break;
1404 }
1405 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001406 return "";
1407}
1408
1409void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1410 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001411}
1412
ethannicholas5961bc92016-10-12 06:39:56 -07001413void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001414 if (!decl.fVars.size()) {
1415 return;
1416 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001417 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001418 for (const auto& stmt : decl.fVars) {
1419 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001420 if (wroteType) {
1421 this->write(", ");
1422 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001423 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001424 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001425 this->writeType(decl.fBaseType);
1426 this->write(" ");
1427 wroteType = true;
1428 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001429 this->write(var.fVar->fName);
1430 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001431 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001432 if (size) {
1433 this->writeExpression(*size, kTopLevel_Precedence);
1434 }
ethannicholasf789b382016-08-03 12:43:36 -07001435 this->write("]");
1436 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001437 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001438 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001439 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001440 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001441 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1442 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001443 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001444 }
Brian Osman061020e2018-04-17 14:22:15 -04001445 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001446 this->writeExtension(
1447 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001448 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001449 fFoundExternalSamplerDecl = true;
1450 }
Brian Salomon67529b22019-08-13 15:31:04 -04001451 if (!fFoundRectSamplerDecl && var.fVar->fType == *fContext.fSampler2DRect_Type) {
1452 fFoundRectSamplerDecl = true;
1453 }
ethannicholasf789b382016-08-03 12:43:36 -07001454 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001455 if (wroteType) {
1456 this->write(";");
1457 }
ethannicholasf789b382016-08-03 12:43:36 -07001458}
1459
1460void GLSLCodeGenerator::writeStatement(const Statement& s) {
1461 switch (s.fKind) {
1462 case Statement::kBlock_Kind:
1463 this->writeBlock((Block&) s);
1464 break;
1465 case Statement::kExpression_Kind:
1466 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1467 this->write(";");
1468 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001469 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001470 this->writeReturnStatement((ReturnStatement&) s);
1471 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001472 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001473 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001474 break;
1475 case Statement::kIf_Kind:
1476 this->writeIfStatement((IfStatement&) s);
1477 break;
1478 case Statement::kFor_Kind:
1479 this->writeForStatement((ForStatement&) s);
1480 break;
1481 case Statement::kWhile_Kind:
1482 this->writeWhileStatement((WhileStatement&) s);
1483 break;
1484 case Statement::kDo_Kind:
1485 this->writeDoStatement((DoStatement&) s);
1486 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001487 case Statement::kSwitch_Kind:
1488 this->writeSwitchStatement((SwitchStatement&) s);
1489 break;
ethannicholasf789b382016-08-03 12:43:36 -07001490 case Statement::kBreak_Kind:
1491 this->write("break;");
1492 break;
1493 case Statement::kContinue_Kind:
1494 this->write("continue;");
1495 break;
1496 case Statement::kDiscard_Kind:
1497 this->write("discard;");
1498 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001499 case Statement::kNop_Kind:
1500 this->write(";");
1501 break;
ethannicholasf789b382016-08-03 12:43:36 -07001502 default:
1503 ABORT("unsupported statement: %s", s.description().c_str());
1504 }
1505}
1506
Ethan Nicholascb670962017-04-20 19:31:52 -04001507void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1508 for (const auto& s : statements) {
1509 if (!s->isEmpty()) {
1510 this->writeStatement(*s);
1511 this->writeLine();
1512 }
1513 }
1514}
1515
ethannicholasf789b382016-08-03 12:43:36 -07001516void GLSLCodeGenerator::writeBlock(const Block& b) {
1517 this->writeLine("{");
1518 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001519 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001520 fIndentation--;
1521 this->write("}");
1522}
1523
1524void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1525 this->write("if (");
1526 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1527 this->write(") ");
1528 this->writeStatement(*stmt.fIfTrue);
1529 if (stmt.fIfFalse) {
1530 this->write(" else ");
1531 this->writeStatement(*stmt.fIfFalse);
1532 }
1533}
1534
1535void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1536 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001537 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001538 this->writeStatement(*f.fInitializer);
1539 } else {
1540 this->write("; ");
1541 }
1542 if (f.fTest) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001543 if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1544 std::unique_ptr<Expression> and_true(new BinaryExpression(
1545 -1, f.fTest->clone(), Token::LOGICALAND,
1546 std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1547 true)),
1548 *fContext.fBool_Type));
1549 this->writeExpression(*and_true, kTopLevel_Precedence);
1550 } else {
1551 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1552 }
ethannicholasf789b382016-08-03 12:43:36 -07001553 }
1554 this->write("; ");
1555 if (f.fNext) {
1556 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1557 }
1558 this->write(") ");
1559 this->writeStatement(*f.fStatement);
1560}
1561
1562void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1563 this->write("while (");
1564 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1565 this->write(") ");
1566 this->writeStatement(*w.fStatement);
1567}
1568
1569void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001570 if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1571 this->write("do ");
1572 this->writeStatement(*d.fStatement);
1573 this->write(" while (");
1574 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1575 this->write(");");
1576 return;
1577 }
1578
1579 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1580 // do {
1581 // CODE;
1582 // } while (CONDITION)
1583 //
1584 // to loops of the form
1585 // bool temp = false;
1586 // while (true) {
1587 // if (temp) {
1588 // if (!CONDITION) {
1589 // break;
1590 // }
1591 // }
1592 // temp = true;
1593 // CODE;
1594 // }
1595 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1596 this->write("bool ");
1597 this->write(tmpVar);
1598 this->writeLine(" = false;");
1599 this->writeLine("while (true) {");
1600 fIndentation++;
1601 this->write("if (");
1602 this->write(tmpVar);
1603 this->writeLine(") {");
1604 fIndentation++;
1605 this->write("if (!");
1606 this->writeExpression(*d.fTest, kPrefix_Precedence);
1607 this->writeLine(") {");
1608 fIndentation++;
1609 this->writeLine("break;");
1610 fIndentation--;
1611 this->writeLine("}");
1612 fIndentation--;
1613 this->writeLine("}");
1614 this->write(tmpVar);
1615 this->writeLine(" = true;");
ethannicholasf789b382016-08-03 12:43:36 -07001616 this->writeStatement(*d.fStatement);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001617 this->writeLine();
1618 fIndentation--;
1619 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001620}
1621
Ethan Nicholasaf197692017-02-27 13:26:45 -05001622void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1623 this->write("switch (");
1624 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1625 this->writeLine(") {");
1626 fIndentation++;
1627 for (const auto& c : s.fCases) {
1628 if (c->fValue) {
1629 this->write("case ");
1630 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1631 this->writeLine(":");
1632 } else {
1633 this->writeLine("default:");
1634 }
1635 fIndentation++;
1636 for (const auto& stmt : c->fStatements) {
1637 this->writeStatement(*stmt);
1638 this->writeLine();
1639 }
1640 fIndentation--;
1641 }
1642 fIndentation--;
1643 this->write("}");
1644}
1645
ethannicholasf789b382016-08-03 12:43:36 -07001646void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1647 this->write("return");
1648 if (r.fExpression) {
1649 this->write(" ");
1650 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1651 }
1652 this->write(";");
1653}
1654
Ethan Nicholas762466e2017-06-29 10:03:38 -04001655void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001656 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001657 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001658}
1659
Ethan Nicholas762466e2017-06-29 10:03:38 -04001660void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1661 switch (e.fKind) {
1662 case ProgramElement::kExtension_Kind:
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001663 this->writeExtension(((Extension&) e).fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001664 break;
1665 case ProgramElement::kVar_Kind: {
1666 VarDeclarations& decl = (VarDeclarations&) e;
1667 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001668 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001669 if (builtin == -1) {
1670 // normal var
1671 this->writeVarDeclarations(decl, true);
1672 this->writeLine();
1673 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001674 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
1675 ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
Brian Salomondc092132018-04-04 10:14:16 -04001676 if (fProgram.fSettings.fFragColorIsInOut) {
1677 this->write("inout ");
1678 } else {
1679 this->write("out ");
1680 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001681 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001682 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001683 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001684 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001685 }
Mike Klein5ce39722017-06-27 22:52:03 +00001686 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001687 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001688 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001689 case ProgramElement::kInterfaceBlock_Kind:
1690 this->writeInterfaceBlock((InterfaceBlock&) e);
1691 break;
1692 case ProgramElement::kFunction_Kind:
1693 this->writeFunction((FunctionDefinition&) e);
1694 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001695 case ProgramElement::kModifiers_Kind: {
1696 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1697 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1698 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001699 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001700 }
1701 fFoundGSInvocations = true;
1702 }
1703 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001704 this->writeLine(";");
1705 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001706 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001707 case ProgramElement::kEnum_Kind:
1708 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001709 default:
1710 printf("%s\n", e.description().c_str());
1711 ABORT("unsupported program element");
Ethan Nicholasc0709392017-06-27 11:20:22 -04001712 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001713}
1714
Ethan Nicholascd700e92018-08-24 16:43:57 -04001715void GLSLCodeGenerator::writeInputVars() {
1716 if (fProgram.fInputs.fRTWidth) {
1717 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1718 fGlobals.writeText("uniform ");
1719 fGlobals.writeText(precision);
1720 fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1721 }
1722 if (fProgram.fInputs.fRTHeight) {
1723 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1724 fGlobals.writeText("uniform ");
1725 fGlobals.writeText(precision);
1726 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1727 }
1728}
1729
Ethan Nicholas762466e2017-06-29 10:03:38 -04001730bool GLSLCodeGenerator::generateCode() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001731 if (fProgramKind != Program::kPipelineStage_Kind) {
1732 this->writeHeader();
1733 }
Chris Dalton8fd79552018-01-11 00:46:14 -05001734 if (Program::kGeometry_Kind == fProgramKind &&
1735 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001736 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001737 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001738 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001739 StringStream body;
1740 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001741 for (const auto& e : fProgram) {
1742 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001743 }
1744 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001745
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001746 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001747 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001748 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001749
1750 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1751 Layout layout;
1752 switch (fProgram.fKind) {
1753 case Program::kVertex_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001754 Modifiers modifiers(layout, Modifiers::kOut_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001755 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001756 if (this->usesPrecisionModifiers()) {
1757 this->write("highp ");
1758 }
Brian Osmancc10d792018-07-20 13:09:45 -04001759 this->write("vec4 sk_FragCoord_Workaround;\n");
1760 break;
1761 }
1762 case Program::kFragment_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001763 Modifiers modifiers(layout, Modifiers::kIn_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001764 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001765 if (this->usesPrecisionModifiers()) {
1766 this->write("highp ");
1767 }
Brian Osmancc10d792018-07-20 13:09:45 -04001768 this->write("vec4 sk_FragCoord_Workaround;\n");
1769 break;
1770 }
1771 default:
1772 break;
1773 }
1774 }
1775
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001776 if (this->usesPrecisionModifiers()) {
1777 this->writeLine("precision mediump float;");
Brian Salomon67529b22019-08-13 15:31:04 -04001778 this->writeLine("precision mediump sampler2D;");
Brian Salomon5a5f3e82019-08-16 15:05:40 -04001779 if (fFoundExternalSamplerDecl &&
1780 !fProgram.fSettings.fCaps->noDefaultPrecisionForExternalSamplers()) {
Brian Salomon67529b22019-08-13 15:31:04 -04001781 this->writeLine("precision mediump samplerExternalOES;");
1782 }
1783 if (fFoundRectSamplerDecl) {
1784 this->writeLine("precision mediump sampler2DRect;");
1785 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001786 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001787 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001788 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001789 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001790}
1791
1792}