blob: e21c32c2c22306f83ebe631f928ba857363d8c9a [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:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500238#ifdef SK_DEBUG
ethannicholasf789b382016-08-03 12:43:36 -0700239 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500240#endif
241 break;
ethannicholasf789b382016-08-03 12:43:36 -0700242 }
243}
244
ethannicholas5961bc92016-10-12 06:39:56 -0700245static bool is_abs(Expression& expr) {
246 if (expr.fKind != Expression::kFunctionCall_Kind) {
247 return false;
248 }
249 return ((FunctionCall&) expr).fFunction.fName == "abs";
250}
251
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500252// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700253// Tegra3 compiler bug.
254void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400255 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400256 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
257 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400258 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.fType) +
259 this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
260 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.fType) +
261 this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700262 this->write("((" + tmpVar1 + " = ");
263 this->writeExpression(absExpr, kTopLevel_Precedence);
264 this->write(") < (" + tmpVar2 + " = ");
265 this->writeExpression(otherExpr, kAssignment_Precedence);
266 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
267}
268
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500269void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
270 this->write("(1.0 / sqrt(");
271 this->writeExpression(x, kTopLevel_Precedence);
272 this->write("))");
273}
274
275void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
276 String name;
277 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
278 name = "_determinant2";
279 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
280 fWrittenIntrinsics.insert(name);
281 fExtraFunctions.writeText((
282 "float " + name + "(mat2 m) {"
283 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
284 "}"
285 ).c_str());
286 }
287 }
288 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
289 name = "_determinant3";
290 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
291 fWrittenIntrinsics.insert(name);
292 fExtraFunctions.writeText((
293 "float " + name + "(mat3 m) {"
294 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
295 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
296 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
297 " float b01 = a22 * a11 - a12 * a21;"
298 " float b11 = -a22 * a10 + a12 * a20;"
299 " float b21 = a21 * a10 - a11 * a20;"
300 " return a00 * b01 + a01 * b11 + a02 * b21;"
301 "}"
302 ).c_str());
303 }
304 }
305 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
306 name = "_determinant3";
307 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
308 fWrittenIntrinsics.insert(name);
309 fExtraFunctions.writeText((
310 "mat4 " + name + "(mat4 m) {"
311 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
312 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
313 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
314 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
315 " float b00 = a00 * a11 - a01 * a10;"
316 " float b01 = a00 * a12 - a02 * a10;"
317 " float b02 = a00 * a13 - a03 * a10;"
318 " float b03 = a01 * a12 - a02 * a11;"
319 " float b04 = a01 * a13 - a03 * a11;"
320 " float b05 = a02 * a13 - a03 * a12;"
321 " float b06 = a20 * a31 - a21 * a30;"
322 " float b07 = a20 * a32 - a22 * a30;"
323 " float b08 = a20 * a33 - a23 * a30;"
324 " float b09 = a21 * a32 - a22 * a31;"
325 " float b10 = a21 * a33 - a23 * a31;"
326 " float b11 = a22 * a33 - a23 * a32;"
327 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
328 "}"
329 ).c_str());
330 }
331 }
332 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400333 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500334 }
335 this->write(name + "(");
336 this->writeExpression(mat, kTopLevel_Precedence);
337 this->write(")");
338}
339
340void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
341 String name;
342 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
343 name = "_inverse2";
344 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
345 fWrittenIntrinsics.insert(name);
346 fExtraFunctions.writeText((
347 "mat2 " + name + "(mat2 m) {"
348 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
349 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
350 "}"
351 ).c_str());
352 }
353 }
354 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
355 name = "_inverse3";
356 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
357 fWrittenIntrinsics.insert(name);
358 fExtraFunctions.writeText((
359 "mat3 " + name + "(mat3 m) {"
360 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
361 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
362 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
363 " float b01 = a22 * a11 - a12 * a21;"
364 " float b11 = -a22 * a10 + a12 * a20;"
365 " float b21 = a21 * a10 - a11 * a20;"
366 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
367 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
368 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
369 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
370 "}"
371 ).c_str());
372 }
373 }
374 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
375 name = "_inverse4";
376 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
377 fWrittenIntrinsics.insert(name);
378 fExtraFunctions.writeText((
379 "mat4 " + name + "(mat4 m) {"
380 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
381 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
382 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
383 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
384 " float b00 = a00 * a11 - a01 * a10;"
385 " float b01 = a00 * a12 - a02 * a10;"
386 " float b02 = a00 * a13 - a03 * a10;"
387 " float b03 = a01 * a12 - a02 * a11;"
388 " float b04 = a01 * a13 - a03 * a11;"
389 " float b05 = a02 * a13 - a03 * a12;"
390 " float b06 = a20 * a31 - a21 * a30;"
391 " float b07 = a20 * a32 - a22 * a30;"
392 " float b08 = a20 * a33 - a23 * a30;"
393 " float b09 = a21 * a32 - a22 * a31;"
394 " float b10 = a21 * a33 - a23 * a31;"
395 " float b11 = a22 * a33 - a23 * a32;"
396 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
397 " b04 * b07 + b05 * b06;"
398 " return mat4("
399 " a11 * b11 - a12 * b10 + a13 * b09,"
400 " a02 * b10 - a01 * b11 - a03 * b09,"
401 " a31 * b05 - a32 * b04 + a33 * b03,"
402 " a22 * b04 - a21 * b05 - a23 * b03,"
403 " a12 * b08 - a10 * b11 - a13 * b07,"
404 " a00 * b11 - a02 * b08 + a03 * b07,"
405 " a32 * b02 - a30 * b05 - a33 * b01,"
406 " a20 * b05 - a22 * b02 + a23 * b01,"
407 " a10 * b10 - a11 * b08 + a13 * b06,"
408 " a01 * b08 - a00 * b10 - a03 * b06,"
409 " a30 * b04 - a31 * b02 + a33 * b00,"
410 " a21 * b02 - a20 * b04 - a23 * b00,"
411 " a11 * b07 - a10 * b09 - a12 * b06,"
412 " a00 * b09 - a01 * b07 + a02 * b06,"
413 " a31 * b01 - a30 * b03 - a32 * b00,"
414 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
415 "}"
416 ).c_str());
417 }
418 }
419 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400420 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500421 }
422 this->write(name + "(");
423 this->writeExpression(mat, kTopLevel_Precedence);
424 this->write(")");
425}
426
427void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
428 String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
429 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
430 fWrittenIntrinsics.insert(name);
431 String type = this->getTypeName(mat.fType);
432 const Type& base = mat.fType.componentType();
433 String transposed = this->getTypeName(base.toCompound(fContext,
434 mat.fType.rows(),
435 mat.fType.columns()));
436 fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
437 transposed + "(").c_str());
438 const char* separator = "";
439 for (int row = 0; row < mat.fType.rows(); ++row) {
440 for (int column = 0; column < mat.fType.columns(); ++column) {
441 fExtraFunctions.writeText(separator);
442 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
443 "]").c_str());
444 separator = ", ";
445 }
446 }
447 fExtraFunctions.writeText("); }");
448 }
449 this->write(name + "(");
450 this->writeExpression(mat, kTopLevel_Precedence);
451 this->write(")");
452}
453
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400454std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
455 GLSLCodeGenerator::fFunctionClasses = nullptr;
456
ethannicholasf789b382016-08-03 12:43:36 -0700457void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400458#ifdef SKSL_STANDALONE
459 if (!fFunctionClasses) {
460#else
461 static SkOnce once;
462 once([] {
463#endif
464 fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
Adrienne Walker92b161f2018-08-22 10:41:52 -0700465 (*fFunctionClasses)["abs"] = FunctionClass::kAbs;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400466 (*fFunctionClasses)["atan"] = FunctionClass::kAtan;
467 (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700468 (*fFunctionClasses)["dFdx"] = FunctionClass::kDFdx;
469 (*fFunctionClasses)["dFdy"] = FunctionClass::kDFdy;
470 (*fFunctionClasses)["fwidth"] = FunctionClass::kFwidth;
Chris Daltona7086182018-11-16 09:33:43 -0500471 (*fFunctionClasses)["fma"] = FunctionClass::kFMA;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400472 (*fFunctionClasses)["fract"] = FunctionClass::kFract;
473 (*fFunctionClasses)["inverse"] = FunctionClass::kInverse;
474 (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
475 (*fFunctionClasses)["min"] = FunctionClass::kMin;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700476 (*fFunctionClasses)["pow"] = FunctionClass::kPow;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400477 (*fFunctionClasses)["saturate"] = FunctionClass::kSaturate;
Ethan Nicholas13863662019-07-29 13:05:15 -0400478 (*fFunctionClasses)["sample"] = FunctionClass::kTexture;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400479 (*fFunctionClasses)["transpose"] = FunctionClass::kTranspose;
ethannicholas5961bc92016-10-12 06:39:56 -0700480 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400481#ifndef SKSL_STANDALONE
482 );
483#endif
484 const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
485 fFunctionClasses->end();
Brian Osman8a83ca42018-02-12 14:32:17 -0500486 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400487 bool nameWritten = false;
488 if (found != fFunctionClasses->end()) {
489 switch (found->second) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700490 case FunctionClass::kAbs: {
491 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
492 break;
493 SkASSERT(c.fArguments.size() == 1);
494 if (c.fArguments[0]->fType != *fContext.fInt_Type)
495 break;
496 // abs(int) on Intel OSX is incorrect, so emulate it:
497 String name = "_absemulation";
498 this->write(name);
499 nameWritten = true;
500 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
501 fWrittenIntrinsics.insert(name);
502 fExtraFunctions.writeText((
503 "int " + name + "(int x) {\n"
504 " return x * sign(x);\n"
505 "}\n"
506 ).c_str());
507 }
508 break;
509 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400510 case FunctionClass::kAtan:
511 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
512 c.fArguments.size() == 2 &&
513 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
514 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400515 if (p.fOperator == Token::Kind::TK_MINUS) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400516 this->write("atan(");
517 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
518 this->write(", -1.0 * ");
519 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
520 this->write(")");
521 return;
522 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500523 }
524 break;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700525 case FunctionClass::kDFdy:
526 if (fProgram.fSettings.fFlipY) {
527 // Flipping Y also negates the Y derivatives.
528 this->write("-dFdy");
529 nameWritten = true;
530 }
531 // fallthru
532 case FunctionClass::kDFdx:
533 case FunctionClass::kFwidth:
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400534 if (!fFoundDerivatives &&
535 fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
536 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
537 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
538 fFoundDerivatives = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500539 }
540 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400541 case FunctionClass::kDeterminant:
542 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
543 SkASSERT(c.fArguments.size() == 1);
544 this->writeDeterminantHack(*c.fArguments[0]);
545 return;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500546 }
547 break;
Chris Daltona7086182018-11-16 09:33:43 -0500548 case FunctionClass::kFMA:
549 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
550 SkASSERT(c.fArguments.size() == 3);
551 this->write("((");
552 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
553 this->write(") * (");
554 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
555 this->write(") + (");
556 this->writeExpression(*c.fArguments[2], kSequence_Precedence);
557 this->write("))");
558 return;
559 }
560 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400561 case FunctionClass::kFract:
562 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
563 SkASSERT(c.fArguments.size() == 1);
564 this->write("(0.5 - sign(");
565 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
566 this->write(") * (0.5 - fract(abs(");
567 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
568 this->write("))))");
569 return;
570 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500571 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400572 case FunctionClass::kInverse:
573 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
574 SkASSERT(c.fArguments.size() == 1);
575 this->writeInverseHack(*c.fArguments[0]);
576 return;
577 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500578 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400579 case FunctionClass::kInverseSqrt:
580 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
581 SkASSERT(c.fArguments.size() == 1);
582 this->writeInverseSqrtHack(*c.fArguments[0]);
583 return;
584 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500585 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400586 case FunctionClass::kMin:
587 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
588 SkASSERT(c.fArguments.size() == 2);
589 if (is_abs(*c.fArguments[0])) {
590 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
591 return;
592 }
593 if (is_abs(*c.fArguments[1])) {
594 // note that this violates the GLSL left-to-right evaluation semantics.
595 // I doubt it will ever end up mattering, but it's worth calling out.
596 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
597 return;
598 }
599 }
600 break;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700601 case FunctionClass::kPow:
602 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
603 break;
604 }
605 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
606 // constant. It's hard to tell what constitutes "constant" here
607 // so just replace in all cases.
608
609 // Change pow(x, y) into exp2(y * log2(x))
610 this->write("exp2(");
611 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
612 this->write(" * log2(");
613 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
614 this->write("))");
615 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400616 case FunctionClass::kSaturate:
617 SkASSERT(c.fArguments.size() == 1);
618 this->write("clamp(");
619 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
620 this->write(", 0.0, 1.0)");
621 return;
622 case FunctionClass::kTexture: {
623 const char* dim = "";
624 bool proj = false;
625 switch (c.fArguments[0]->fType.dimensions()) {
626 case SpvDim1D:
627 dim = "1D";
628 isTextureFunctionWithBias = true;
629 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
630 proj = false;
631 } else {
632 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
633 proj = true;
634 }
635 break;
636 case SpvDim2D:
637 dim = "2D";
638 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
639 isTextureFunctionWithBias = true;
640 }
641 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
642 proj = false;
643 } else {
644 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
645 proj = true;
646 }
647 break;
648 case SpvDim3D:
649 dim = "3D";
650 isTextureFunctionWithBias = true;
651 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
652 proj = false;
653 } else {
654 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
655 proj = true;
656 }
657 break;
658 case SpvDimCube:
659 dim = "Cube";
660 isTextureFunctionWithBias = true;
661 proj = false;
662 break;
663 case SpvDimRect:
Khushal Sagar2cb13152019-09-11 23:17:26 +0000664 dim = "2DRect";
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400665 proj = false;
666 break;
667 case SpvDimBuffer:
668 SkASSERT(false); // doesn't exist
669 dim = "Buffer";
670 proj = false;
671 break;
672 case SpvDimSubpassData:
673 SkASSERT(false); // doesn't exist
674 dim = "SubpassData";
675 proj = false;
676 break;
677 }
Ethan Nicholas13863662019-07-29 13:05:15 -0400678 if (fTextureFunctionOverride != "") {
679 this->write(fTextureFunctionOverride.c_str());
680 } else {
681 this->write("texture");
682 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
683 this->write(dim);
684 }
685 if (proj) {
686 this->write("Proj");
687 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400688 }
689 nameWritten = true;
690 break;
691 }
692 case FunctionClass::kTranspose:
693 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
694 SkASSERT(c.fArguments.size() == 1);
695 this->writeTransposeHack(*c.fArguments[0]);
696 return;
697 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500698 break;
699 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400700 }
701 if (!nameWritten) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500702 this->write(c.fFunction.fName);
703 }
704 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700705 const char* separator = "";
706 for (const auto& arg : c.fArguments) {
707 this->write(separator);
708 separator = ", ";
709 this->writeExpression(*arg, kSequence_Precedence);
710 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500711 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
712 this->write(", -0.5");
713 }
ethannicholasf789b382016-08-03 12:43:36 -0700714 this->write(")");
715}
716
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400717void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
718 if (c.fArguments.size() == 1 &&
Ethan Nicholase1f55022019-02-05 17:17:40 -0500719 (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
720 (c.fType.kind() == Type::kScalar_Kind &&
721 c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400722 // in cases like half(float), they're different types as far as SkSL is concerned but the
723 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
724 // out the inner expression here.
725 this->writeExpression(*c.fArguments[0], parentPrecedence);
726 return;
727 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400728 this->writeType(c.fType);
729 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700730 const char* separator = "";
731 for (const auto& arg : c.fArguments) {
732 this->write(separator);
733 separator = ", ";
734 this->writeExpression(*arg, kSequence_Precedence);
735 }
736 this->write(")");
737}
738
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500739void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000740 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500741 if (!fSetupFragCoordWorkaround) {
742 const char* precision = usesPrecisionModifiers() ? "highp " : "";
743 fFunctionHeader += precision;
744 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
745 fFunctionHeader += precision;
746 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
747 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
748 // Ensure that we get exact .5 values for x and y.
749 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
750 "vec2(.5);\n";
751 fSetupFragCoordWorkaround = true;
752 }
753 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000754 return;
755 }
756
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500757 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
758 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
759 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
760 if (!fProgram.fSettings.fFlipY) {
761 this->write("gl_FragCoord");
762 } else if (const char* extension =
Ethan Nicholascd700e92018-08-24 16:43:57 -0400763 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500764 if (!fSetupFragPositionGlobal) {
765 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400766 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500767 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400768 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500769 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000770 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500771 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000772 } else {
Ethan Nicholascd700e92018-08-24 16:43:57 -0400773 if (!fSetupFragPositionLocal) {
Michael Ludwig5e1f6ea2018-12-03 15:14:50 -0500774 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
Michael Ludwigf0b60442018-12-10 14:43:38 +0000775 fFunctionHeader += " vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
776 " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500777 fSetupFragPositionLocal = true;
778 }
779 this->write("sk_FragCoord");
780 }
781}
782
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500783void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
784 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
785 case SK_FRAGCOLOR_BUILTIN:
786 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
787 this->write("sk_FragColor");
788 } else {
789 this->write("gl_FragColor");
790 }
791 break;
792 case SK_FRAGCOORD_BUILTIN:
793 this->writeFragCoord();
794 break;
Ethan Nicholascd700e92018-08-24 16:43:57 -0400795 case SK_WIDTH_BUILTIN:
796 this->write("u_skRTWidth");
797 break;
798 case SK_HEIGHT_BUILTIN:
799 this->write("u_skRTHeight");
800 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600801 case SK_CLOCKWISE_BUILTIN:
Chris Daltonc8ece3d2018-07-30 15:03:45 -0600802 this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
Chris Dalton49d14e92018-07-27 12:38:35 -0600803 break;
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600804 case SK_SAMPLEMASK_BUILTIN:
Chris Dalton8a64a442019-10-29 18:54:58 -0600805 SkASSERT(fProgram.fSettings.fCaps->sampleMaskSupport());
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600806 this->write("gl_SampleMask");
807 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500808 case SK_VERTEXID_BUILTIN:
809 this->write("gl_VertexID");
810 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600811 case SK_INSTANCEID_BUILTIN:
812 this->write("gl_InstanceID");
813 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500814 case SK_CLIPDISTANCE_BUILTIN:
815 this->write("gl_ClipDistance");
816 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500817 case SK_IN_BUILTIN:
818 this->write("gl_in");
819 break;
820 case SK_INVOCATIONID_BUILTIN:
821 this->write("gl_InvocationID");
822 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400823 case SK_LASTFRAGCOLOR_BUILTIN:
824 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
825 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500826 default:
827 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700828 }
ethannicholasf789b382016-08-03 12:43:36 -0700829}
830
831void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
832 this->writeExpression(*expr.fBase, kPostfix_Precedence);
833 this->write("[");
834 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
835 this->write("]");
836}
837
Brian Osmancd3261a2018-01-16 13:52:29 +0000838bool is_sk_position(const FieldAccess& f) {
839 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
840}
841
ethannicholasf789b382016-08-03 12:43:36 -0700842void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
843 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
844 this->writeExpression(*f.fBase, kPostfix_Precedence);
845 this->write(".");
846 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500847 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
848 case SK_CLIPDISTANCE_BUILTIN:
849 this->write("gl_ClipDistance");
850 break;
851 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400852 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
853 if (name == "sk_Position") {
854 this->write("gl_Position");
855 } else if (name == "sk_PointSize") {
856 this->write("gl_PointSize");
857 } else {
858 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
859 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500860 }
ethannicholasf789b382016-08-03 12:43:36 -0700861}
862
Ethan Nicholase455f652019-09-13 12:52:55 -0400863void GLSLCodeGenerator::writeConstantSwizzle(const Swizzle& swizzle, const String& constants) {
864 this->writeType(swizzle.fType);
865 this->write("(");
866 this->write(constants);
867 this->write(")");
868}
869
870void GLSLCodeGenerator::writeSwizzleMask(const Swizzle& swizzle, const String& mask) {
ethannicholasf789b382016-08-03 12:43:36 -0700871 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
872 this->write(".");
Ethan Nicholase455f652019-09-13 12:52:55 -0400873 this->write(mask);
874}
875
876void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
877 const String& mask,
878 GLSLCodeGenerator::SwizzleOrder order) {
879 this->writeType(swizzle.fType);
880 this->write("(");
881 if (order == SwizzleOrder::CONSTANTS_FIRST) {
882 this->write(constants);
883 this->write(", ");
884 this->writeSwizzleMask(swizzle, mask);
885 } else {
886 this->writeSwizzleMask(swizzle, mask);
887 this->write(", ");
888 this->write(constants);
889 }
890 this->write(")");
891}
892
893void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
894 const String& mask, const String& reswizzle) {
895 this->writeSwizzleConstructor(swizzle, constants, mask, SwizzleOrder::MASK_FIRST);
896 this->write(".");
897 this->write(reswizzle);
898}
899
900// Writing a swizzle is complicated due to the handling of constant swizzle components. The most
901// problematic case is a mask like '.r00a'. A naive approach might turn that into
902// 'vec4(base.r, 0, 0, base.a)', but that would cause 'base' to be evaluated twice. We instead
903// group the swizzle mask ('ra') and constants ('0, 0') together and use a secondary swizzle to put
904// them back into the right order, so in this case we end up with something like
905// 'vec4(base4.ra, 0, 0).rbag'.
906void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
907 // has a 1 bit in every position for which the swizzle mask is a constant, so 'r0b1' would
908 // yield binary 0101.
909 int constantBits = 0;
910 String mask;
911 String constants;
912 // compute mask ("ra") and constant ("0, 0") strings, and fill in constantBits
ethannicholasf789b382016-08-03 12:43:36 -0700913 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -0400914 constantBits <<= 1;
915 switch (c) {
916 case SKSL_SWIZZLE_0:
917 constantBits |= 1;
918 if (constants.length() > 0) {
919 constants += ", ";
920 }
921 constants += "0";
922 break;
923 case SKSL_SWIZZLE_1:
924 constantBits |= 1;
925 if (constants.length() > 0) {
926 constants += ", ";
927 }
928 constants += "1";
929 break;
930 case 0:
931 mask += "x";
932 break;
933 case 1:
934 mask += "y";
935 break;
936 case 2:
937 mask += "z";
938 break;
939 case 3:
940 mask += "w";
941 break;
942 default:
943 SkASSERT(false);
Ethan Nicholasac285b12019-02-12 16:05:18 -0500944 }
945 }
Ethan Nicholase455f652019-09-13 12:52:55 -0400946 switch (swizzle.fComponents.size()) {
947 case 1:
948 if (constantBits == 1) {
949 this->write(constants);
950 }
951 else {
952 this->writeSwizzleMask(swizzle, mask);
953 }
954 break;
955 case 2:
956 switch (constantBits) {
957 case 0: // 00
958 this->writeSwizzleMask(swizzle, mask);
959 break;
960 case 1: // 01
961 this->writeSwizzleConstructor(swizzle, constants, mask,
962 SwizzleOrder::MASK_FIRST);
963 break;
964 case 2: // 10
965 this->writeSwizzleConstructor(swizzle, constants, mask,
966 SwizzleOrder::CONSTANTS_FIRST);
967 break;
968 case 3: // 11
969 this->writeConstantSwizzle(swizzle, constants);
970 break;
971 default:
972 SkASSERT(false);
973 }
974 break;
975 case 3:
976 switch (constantBits) {
977 case 0: // 000
978 this->writeSwizzleMask(swizzle, mask);
979 break;
980 case 1: // 001
981 case 3: // 011
982 this->writeSwizzleConstructor(swizzle, constants, mask,
983 SwizzleOrder::MASK_FIRST);
984 break;
985 case 4: // 100
986 case 6: // 110
987 this->writeSwizzleConstructor(swizzle, constants, mask,
988 SwizzleOrder::CONSTANTS_FIRST);
989 break;
990 case 2: // 010
991 this->writeSwizzleConstructor(swizzle, constants, mask, "xzy");
992 break;
993 case 5: // 101
994 this->writeSwizzleConstructor(swizzle, constants, mask, "yxz");
995 break;
996 case 7: // 111
997 this->writeConstantSwizzle(swizzle, constants);
998 break;
999 }
1000 break;
1001 case 4:
1002 switch (constantBits) {
1003 case 0: // 0000
1004 this->writeSwizzleMask(swizzle, mask);
1005 break;
1006 case 1: // 0001
1007 case 3: // 0011
1008 case 7: // 0111
1009 this->writeSwizzleConstructor(swizzle, constants, mask,
1010 SwizzleOrder::MASK_FIRST);
1011 break;
1012 case 8: // 1000
1013 case 12: // 1100
1014 case 14: // 1110
1015 this->writeSwizzleConstructor(swizzle, constants, mask,
1016 SwizzleOrder::CONSTANTS_FIRST);
1017 break;
1018 case 2: // 0010
1019 this->writeSwizzleConstructor(swizzle, constants, mask, "xywz");
1020 break;
1021 case 4: // 0100
1022 this->writeSwizzleConstructor(swizzle, constants, mask, "xwyz");
1023 break;
1024 case 5: // 0101
1025 this->writeSwizzleConstructor(swizzle, constants, mask, "xzyw");
1026 break;
1027 case 6: // 0110
1028 this->writeSwizzleConstructor(swizzle, constants, mask, "xzwy");
1029 break;
1030 case 9: // 1001
1031 this->writeSwizzleConstructor(swizzle, constants, mask, "zxyw");
1032 break;
1033 case 10: // 1010
1034 this->writeSwizzleConstructor(swizzle, constants, mask, "zxwy");
1035 break;
1036 case 11: // 1011
1037 this->writeSwizzleConstructor(swizzle, constants, mask, "yxzw");
1038 break;
1039 case 13: // 1101
1040 this->writeSwizzleConstructor(swizzle, constants, mask, "yzxw");
1041 break;
1042 case 15: // 1111
1043 this->writeConstantSwizzle(swizzle, constants);
1044 break;
1045 }
ethannicholasf789b382016-08-03 12:43:36 -07001046 }
1047}
1048
Ethan Nicholas762466e2017-06-29 10:03:38 -04001049GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -07001050 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001051 case Token::Kind::TK_STAR: // fall through
1052 case Token::Kind::TK_SLASH: // fall through
1053 case Token::Kind::TK_PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
1054 case Token::Kind::TK_PLUS: // fall through
1055 case Token::Kind::TK_MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
1056 case Token::Kind::TK_SHL: // fall through
1057 case Token::Kind::TK_SHR: return GLSLCodeGenerator::kShift_Precedence;
1058 case Token::Kind::TK_LT: // fall through
1059 case Token::Kind::TK_GT: // fall through
1060 case Token::Kind::TK_LTEQ: // fall through
1061 case Token::Kind::TK_GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
1062 case Token::Kind::TK_EQEQ: // fall through
1063 case Token::Kind::TK_NEQ: return GLSLCodeGenerator::kEquality_Precedence;
1064 case Token::Kind::TK_BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
1065 case Token::Kind::TK_BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
1066 case Token::Kind::TK_BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
1067 case Token::Kind::TK_LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
1068 case Token::Kind::TK_LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
1069 case Token::Kind::TK_LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
1070 case Token::Kind::TK_EQ: // fall through
1071 case Token::Kind::TK_PLUSEQ: // fall through
1072 case Token::Kind::TK_MINUSEQ: // fall through
1073 case Token::Kind::TK_STAREQ: // fall through
1074 case Token::Kind::TK_SLASHEQ: // fall through
1075 case Token::Kind::TK_PERCENTEQ: // fall through
1076 case Token::Kind::TK_SHLEQ: // fall through
1077 case Token::Kind::TK_SHREQ: // fall through
1078 case Token::Kind::TK_LOGICALANDEQ: // fall through
1079 case Token::Kind::TK_LOGICALXOREQ: // fall through
1080 case Token::Kind::TK_LOGICALOREQ: // fall through
1081 case Token::Kind::TK_BITWISEANDEQ: // fall through
1082 case Token::Kind::TK_BITWISEXOREQ: // fall through
1083 case Token::Kind::TK_BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
1084 case Token::Kind::TK_COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -07001085 default: ABORT("unsupported binary operator");
1086 }
1087}
1088
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001089void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -07001090 Precedence parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001091 if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001092 (b.fOperator == Token::Kind::TK_LOGICALAND ||
1093 b.fOperator == Token::Kind::TK_LOGICALOR)) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001094 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
1095 return;
1096 }
1097
Ethan Nicholas762466e2017-06-29 10:03:38 -04001098 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -07001099 if (precedence >= parentPrecedence) {
1100 this->write("(");
1101 }
Ethan Nicholas0b631962018-07-24 13:41:11 -04001102 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
1103 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +00001104 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
1105 is_sk_position((FieldAccess&) *b.fLeft) &&
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001106 !b.fRight->containsRTAdjust() &&
Brian Osmancd3261a2018-01-16 13:52:29 +00001107 !fProgram.fSettings.fCaps->canUseFragCoord();
1108 if (positionWorkaround) {
1109 this->write("sk_FragCoord_Workaround = (");
1110 }
ethannicholasf789b382016-08-03 12:43:36 -07001111 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001112 this->write(" ");
1113 this->write(Compiler::OperatorName(b.fOperator));
1114 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -07001115 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +00001116 if (positionWorkaround) {
1117 this->write(")");
1118 }
ethannicholasf789b382016-08-03 12:43:36 -07001119 if (precedence >= parentPrecedence) {
1120 this->write(")");
1121 }
1122}
1123
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001124void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
1125 Precedence parentPrecedence) {
1126 if (kTernary_Precedence >= parentPrecedence) {
1127 this->write("(");
1128 }
1129
1130 // Transform:
1131 // a && b => a ? b : false
1132 // a || b => a ? true : b
1133 this->writeExpression(*b.fLeft, kTernary_Precedence);
1134 this->write(" ? ");
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001135 if (b.fOperator == Token::Kind::TK_LOGICALAND) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001136 this->writeExpression(*b.fRight, kTernary_Precedence);
1137 } else {
1138 BoolLiteral boolTrue(fContext, -1, true);
1139 this->writeBoolLiteral(boolTrue);
1140 }
1141 this->write(" : ");
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001142 if (b.fOperator == Token::Kind::TK_LOGICALAND) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001143 BoolLiteral boolFalse(fContext, -1, false);
1144 this->writeBoolLiteral(boolFalse);
1145 } else {
1146 this->writeExpression(*b.fRight, kTernary_Precedence);
1147 }
1148 if (kTernary_Precedence >= parentPrecedence) {
1149 this->write(")");
1150 }
1151}
1152
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001153void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -07001154 Precedence parentPrecedence) {
1155 if (kTernary_Precedence >= parentPrecedence) {
1156 this->write("(");
1157 }
1158 this->writeExpression(*t.fTest, kTernary_Precedence);
1159 this->write(" ? ");
1160 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
1161 this->write(" : ");
1162 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
1163 if (kTernary_Precedence >= parentPrecedence) {
1164 this->write(")");
1165 }
1166}
1167
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001168void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001169 Precedence parentPrecedence) {
1170 if (kPrefix_Precedence >= parentPrecedence) {
1171 this->write("(");
1172 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001173 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001174 this->writeExpression(*p.fOperand, kPrefix_Precedence);
1175 if (kPrefix_Precedence >= parentPrecedence) {
1176 this->write(")");
1177 }
1178}
1179
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001180void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001181 Precedence parentPrecedence) {
1182 if (kPostfix_Precedence >= parentPrecedence) {
1183 this->write("(");
1184 }
1185 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001186 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001187 if (kPostfix_Precedence >= parentPrecedence) {
1188 this->write(")");
1189 }
1190}
1191
1192void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1193 this->write(b.fValue ? "true" : "false");
1194}
1195
1196void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -07001197 if (i.fType == *fContext.fUInt_Type) {
1198 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -05001199 } else if (i.fType == *fContext.fUShort_Type) {
1200 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001201 } else if (i.fType == *fContext.fUByte_Type) {
1202 this->write(to_string(i.fValue & 0xff) + "u");
1203 } else {
ethannicholas5961bc92016-10-12 06:39:56 -07001204 this->write(to_string((int32_t) i.fValue));
1205 }
ethannicholasf789b382016-08-03 12:43:36 -07001206}
1207
1208void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1209 this->write(to_string(f.fValue));
1210}
1211
Ethan Nicholas762466e2017-06-29 10:03:38 -04001212void GLSLCodeGenerator::writeSetting(const Setting& s) {
1213 ABORT("internal error; setting was not folded to a constant during compilation\n");
1214}
1215
ethannicholasf789b382016-08-03 12:43:36 -07001216void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholasc6dce5a2019-07-24 16:51:36 -04001217 fSetupFragPositionLocal = false;
1218 fSetupFragCoordWorkaround = false;
Ethan Nicholas00543112018-07-31 09:44:36 -04001219 if (fProgramKind != Program::kPipelineStage_Kind) {
1220 this->writeTypePrecision(f.fDeclaration.fReturnType);
1221 this->writeType(f.fDeclaration.fReturnType);
1222 this->write(" " + f.fDeclaration.fName + "(");
1223 const char* separator = "";
1224 for (const auto& param : f.fDeclaration.fParameters) {
1225 this->write(separator);
1226 separator = ", ";
1227 this->writeModifiers(param->fModifiers, false);
1228 std::vector<int> sizes;
1229 const Type* type = &param->fType;
1230 while (type->kind() == Type::kArray_Kind) {
1231 sizes.push_back(type->columns());
1232 type = &type->componentType();
1233 }
1234 this->writeTypePrecision(*type);
1235 this->writeType(*type);
1236 this->write(" " + param->fName);
1237 for (int s : sizes) {
1238 if (s <= 0) {
1239 this->write("[]");
1240 } else {
1241 this->write("[" + to_string(s) + "]");
1242 }
ethannicholas5961bc92016-10-12 06:39:56 -07001243 }
1244 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001245 this->writeLine(") {");
1246 fIndentation++;
ethannicholasf789b382016-08-03 12:43:36 -07001247 }
ethannicholas5961bc92016-10-12 06:39:56 -07001248 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001249 OutputStream* oldOut = fOut;
1250 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001251 fOut = &buffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04001252 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas00543112018-07-31 09:44:36 -04001253 if (fProgramKind != Program::kPipelineStage_Kind) {
1254 fIndentation--;
1255 this->writeLine("}");
1256 }
ethannicholas5961bc92016-10-12 06:39:56 -07001257
1258 fOut = oldOut;
1259 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001260 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001261}
1262
Greg Daniel64773e62016-11-22 09:44:03 -05001263void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001264 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001265 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1266 this->write("flat ");
1267 }
ethannicholas5961bc92016-10-12 06:39:56 -07001268 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1269 this->write("noperspective ");
1270 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001271 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001272 if (layout.size()) {
1273 this->write(layout + " ");
1274 }
Brian Salomonf9f45122016-11-29 11:59:17 -05001275 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1276 this->write("readonly ");
1277 }
1278 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1279 this->write("writeonly ");
1280 }
1281 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1282 this->write("coherent ");
1283 }
1284 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1285 this->write("volatile ");
1286 }
1287 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1288 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -07001289 }
Greg Daniel64773e62016-11-22 09:44:03 -05001290 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001291 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1292 this->write("inout ");
1293 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001294 if (globalContext &&
1295 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001296 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1297 : "varying ");
1298 } else {
1299 this->write("in ");
1300 }
1301 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001302 if (globalContext &&
1303 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001304 this->write("varying ");
1305 } else {
1306 this->write("out ");
1307 }
1308 }
1309 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1310 this->write("uniform ");
1311 }
1312 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1313 this->write("const ");
1314 }
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001315 if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1316 this->write("__pixel_localEXT ");
1317 }
1318 if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1319 this->write("__pixel_local_inEXT ");
1320 }
1321 if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1322 this->write("__pixel_local_outEXT ");
1323 }
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001324 switch (modifiers.fLayout.fFormat) {
1325 case Layout::Format::kUnspecified:
1326 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001327 case Layout::Format::kRGBA32F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001328 case Layout::Format::kR32F:
ethannicholas5961bc92016-10-12 06:39:56 -07001329 this->write("highp ");
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001330 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001331 case Layout::Format::kRGBA16F: // fall through
1332 case Layout::Format::kR16F: // fall through
1333 case Layout::Format::kLUMINANCE16F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001334 case Layout::Format::kRG16F:
1335 this->write("mediump ");
1336 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001337 case Layout::Format::kRGBA8: // fall through
1338 case Layout::Format::kR8: // fall through
1339 case Layout::Format::kRGBA8I: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001340 case Layout::Format::kR8I:
1341 this->write("lowp ");
1342 break;
ethannicholas5961bc92016-10-12 06:39:56 -07001343 }
ethannicholasf789b382016-08-03 12:43:36 -07001344}
1345
1346void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001347 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001348 return;
1349 }
ethannicholas5961bc92016-10-12 06:39:56 -07001350 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001351 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001352 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001353 const Type* structType = &intf.fVariable.fType;
1354 while (structType->kind() == Type::kArray_Kind) {
1355 structType = &structType->componentType();
1356 }
1357 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001358 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001359 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001360 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001361 this->writeLine(" " + f.fName + ";");
1362 }
1363 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001364 this->write("}");
1365 if (intf.fInstanceName.size()) {
1366 this->write(" ");
1367 this->write(intf.fInstanceName);
1368 for (const auto& size : intf.fSizes) {
1369 this->write("[");
1370 if (size) {
1371 this->writeExpression(*size, kTopLevel_Precedence);
1372 }
1373 this->write("]");
1374 }
1375 }
1376 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001377}
1378
Ethan Nicholas762466e2017-06-29 10:03:38 -04001379void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1380 this->writeExpression(value, kTopLevel_Precedence);
1381}
1382
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001383const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1384 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001385 switch (type.kind()) {
1386 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001387 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1388 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001389 if (fProgram.fSettings.fForceHighPrecision ||
1390 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1391 return "highp ";
1392 }
1393 return "mediump ";
1394 }
1395 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001396 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001397 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001398 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1399 type == *fContext.fUInt_Type) {
1400 return "highp ";
1401 }
1402 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001403 case Type::kVector_Kind: // fall through
1404 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001405 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001406 default:
1407 break;
1408 }
1409 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001410 return "";
1411}
1412
1413void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1414 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001415}
1416
ethannicholas5961bc92016-10-12 06:39:56 -07001417void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001418 if (!decl.fVars.size()) {
1419 return;
1420 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001421 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001422 for (const auto& stmt : decl.fVars) {
1423 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001424 if (wroteType) {
1425 this->write(", ");
1426 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001427 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001428 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001429 this->writeType(decl.fBaseType);
1430 this->write(" ");
1431 wroteType = true;
1432 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001433 this->write(var.fVar->fName);
1434 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001435 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001436 if (size) {
1437 this->writeExpression(*size, kTopLevel_Precedence);
1438 }
ethannicholasf789b382016-08-03 12:43:36 -07001439 this->write("]");
1440 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001441 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001442 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001443 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001444 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001445 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1446 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001447 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001448 }
Brian Osman061020e2018-04-17 14:22:15 -04001449 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001450 this->writeExtension(
1451 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001452 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001453 fFoundExternalSamplerDecl = true;
1454 }
Brian Salomon67529b22019-08-13 15:31:04 -04001455 if (!fFoundRectSamplerDecl && var.fVar->fType == *fContext.fSampler2DRect_Type) {
1456 fFoundRectSamplerDecl = true;
1457 }
ethannicholasf789b382016-08-03 12:43:36 -07001458 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001459 if (wroteType) {
1460 this->write(";");
1461 }
ethannicholasf789b382016-08-03 12:43:36 -07001462}
1463
1464void GLSLCodeGenerator::writeStatement(const Statement& s) {
1465 switch (s.fKind) {
1466 case Statement::kBlock_Kind:
1467 this->writeBlock((Block&) s);
1468 break;
1469 case Statement::kExpression_Kind:
1470 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1471 this->write(";");
1472 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001473 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001474 this->writeReturnStatement((ReturnStatement&) s);
1475 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001476 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001477 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001478 break;
1479 case Statement::kIf_Kind:
1480 this->writeIfStatement((IfStatement&) s);
1481 break;
1482 case Statement::kFor_Kind:
1483 this->writeForStatement((ForStatement&) s);
1484 break;
1485 case Statement::kWhile_Kind:
1486 this->writeWhileStatement((WhileStatement&) s);
1487 break;
1488 case Statement::kDo_Kind:
1489 this->writeDoStatement((DoStatement&) s);
1490 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001491 case Statement::kSwitch_Kind:
1492 this->writeSwitchStatement((SwitchStatement&) s);
1493 break;
ethannicholasf789b382016-08-03 12:43:36 -07001494 case Statement::kBreak_Kind:
1495 this->write("break;");
1496 break;
1497 case Statement::kContinue_Kind:
1498 this->write("continue;");
1499 break;
1500 case Statement::kDiscard_Kind:
1501 this->write("discard;");
1502 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001503 case Statement::kNop_Kind:
1504 this->write(";");
1505 break;
ethannicholasf789b382016-08-03 12:43:36 -07001506 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001507#ifdef SK_DEBUG
ethannicholasf789b382016-08-03 12:43:36 -07001508 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001509#endif
1510 break;
ethannicholasf789b382016-08-03 12:43:36 -07001511 }
1512}
1513
Ethan Nicholascb670962017-04-20 19:31:52 -04001514void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1515 for (const auto& s : statements) {
1516 if (!s->isEmpty()) {
1517 this->writeStatement(*s);
1518 this->writeLine();
1519 }
1520 }
1521}
1522
ethannicholasf789b382016-08-03 12:43:36 -07001523void GLSLCodeGenerator::writeBlock(const Block& b) {
1524 this->writeLine("{");
1525 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001526 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001527 fIndentation--;
1528 this->write("}");
1529}
1530
1531void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1532 this->write("if (");
1533 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1534 this->write(") ");
1535 this->writeStatement(*stmt.fIfTrue);
1536 if (stmt.fIfFalse) {
1537 this->write(" else ");
1538 this->writeStatement(*stmt.fIfFalse);
1539 }
1540}
1541
1542void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1543 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001544 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001545 this->writeStatement(*f.fInitializer);
1546 } else {
1547 this->write("; ");
1548 }
1549 if (f.fTest) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001550 if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1551 std::unique_ptr<Expression> and_true(new BinaryExpression(
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001552 -1, f.fTest->clone(), Token::Kind::TK_LOGICALAND,
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001553 std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1554 true)),
1555 *fContext.fBool_Type));
1556 this->writeExpression(*and_true, kTopLevel_Precedence);
1557 } else {
1558 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1559 }
ethannicholasf789b382016-08-03 12:43:36 -07001560 }
1561 this->write("; ");
1562 if (f.fNext) {
1563 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1564 }
1565 this->write(") ");
1566 this->writeStatement(*f.fStatement);
1567}
1568
1569void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1570 this->write("while (");
1571 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1572 this->write(") ");
1573 this->writeStatement(*w.fStatement);
1574}
1575
1576void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001577 if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1578 this->write("do ");
1579 this->writeStatement(*d.fStatement);
1580 this->write(" while (");
1581 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1582 this->write(");");
1583 return;
1584 }
1585
1586 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1587 // do {
1588 // CODE;
1589 // } while (CONDITION)
1590 //
1591 // to loops of the form
1592 // bool temp = false;
1593 // while (true) {
1594 // if (temp) {
1595 // if (!CONDITION) {
1596 // break;
1597 // }
1598 // }
1599 // temp = true;
1600 // CODE;
1601 // }
1602 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1603 this->write("bool ");
1604 this->write(tmpVar);
1605 this->writeLine(" = false;");
1606 this->writeLine("while (true) {");
1607 fIndentation++;
1608 this->write("if (");
1609 this->write(tmpVar);
1610 this->writeLine(") {");
1611 fIndentation++;
1612 this->write("if (!");
1613 this->writeExpression(*d.fTest, kPrefix_Precedence);
1614 this->writeLine(") {");
1615 fIndentation++;
1616 this->writeLine("break;");
1617 fIndentation--;
1618 this->writeLine("}");
1619 fIndentation--;
1620 this->writeLine("}");
1621 this->write(tmpVar);
1622 this->writeLine(" = true;");
ethannicholasf789b382016-08-03 12:43:36 -07001623 this->writeStatement(*d.fStatement);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001624 this->writeLine();
1625 fIndentation--;
1626 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001627}
1628
Ethan Nicholasaf197692017-02-27 13:26:45 -05001629void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1630 this->write("switch (");
1631 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1632 this->writeLine(") {");
1633 fIndentation++;
1634 for (const auto& c : s.fCases) {
1635 if (c->fValue) {
1636 this->write("case ");
1637 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1638 this->writeLine(":");
1639 } else {
1640 this->writeLine("default:");
1641 }
1642 fIndentation++;
1643 for (const auto& stmt : c->fStatements) {
1644 this->writeStatement(*stmt);
1645 this->writeLine();
1646 }
1647 fIndentation--;
1648 }
1649 fIndentation--;
1650 this->write("}");
1651}
1652
ethannicholasf789b382016-08-03 12:43:36 -07001653void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1654 this->write("return");
1655 if (r.fExpression) {
1656 this->write(" ");
1657 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1658 }
1659 this->write(";");
1660}
1661
Ethan Nicholas762466e2017-06-29 10:03:38 -04001662void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001663 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001664 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001665}
1666
Ethan Nicholas762466e2017-06-29 10:03:38 -04001667void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1668 switch (e.fKind) {
1669 case ProgramElement::kExtension_Kind:
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001670 this->writeExtension(((Extension&) e).fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001671 break;
1672 case ProgramElement::kVar_Kind: {
1673 VarDeclarations& decl = (VarDeclarations&) e;
1674 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001675 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001676 if (builtin == -1) {
1677 // normal var
1678 this->writeVarDeclarations(decl, true);
1679 this->writeLine();
1680 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001681 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
1682 ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
Brian Salomondc092132018-04-04 10:14:16 -04001683 if (fProgram.fSettings.fFragColorIsInOut) {
1684 this->write("inout ");
1685 } else {
1686 this->write("out ");
1687 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001688 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001689 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001690 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001691 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001692 }
Mike Klein5ce39722017-06-27 22:52:03 +00001693 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001694 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001695 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001696 case ProgramElement::kInterfaceBlock_Kind:
1697 this->writeInterfaceBlock((InterfaceBlock&) e);
1698 break;
1699 case ProgramElement::kFunction_Kind:
1700 this->writeFunction((FunctionDefinition&) e);
1701 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001702 case ProgramElement::kModifiers_Kind: {
1703 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1704 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1705 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001706 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001707 }
1708 fFoundGSInvocations = true;
1709 }
1710 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001711 this->writeLine(";");
1712 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001713 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001714 case ProgramElement::kEnum_Kind:
1715 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001716 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001717#ifdef SK_DEBUG
1718 printf("unsupported program element %s\n", e.description().c_str());
1719#endif
1720 SkASSERT(false);
Ethan Nicholasc0709392017-06-27 11:20:22 -04001721 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001722}
1723
Ethan Nicholascd700e92018-08-24 16:43:57 -04001724void GLSLCodeGenerator::writeInputVars() {
1725 if (fProgram.fInputs.fRTWidth) {
1726 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1727 fGlobals.writeText("uniform ");
1728 fGlobals.writeText(precision);
1729 fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1730 }
1731 if (fProgram.fInputs.fRTHeight) {
1732 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1733 fGlobals.writeText("uniform ");
1734 fGlobals.writeText(precision);
1735 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1736 }
1737}
1738
Ethan Nicholas762466e2017-06-29 10:03:38 -04001739bool GLSLCodeGenerator::generateCode() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001740 if (fProgramKind != Program::kPipelineStage_Kind) {
1741 this->writeHeader();
1742 }
Chris Dalton8fd79552018-01-11 00:46:14 -05001743 if (Program::kGeometry_Kind == fProgramKind &&
1744 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001745 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001746 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001747 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001748 StringStream body;
1749 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001750 for (const auto& e : fProgram) {
1751 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001752 }
1753 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001754
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001755 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001756 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001757 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001758
1759 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1760 Layout layout;
1761 switch (fProgram.fKind) {
1762 case Program::kVertex_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001763 Modifiers modifiers(layout, Modifiers::kOut_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 case Program::kFragment_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001772 Modifiers modifiers(layout, Modifiers::kIn_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001773 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001774 if (this->usesPrecisionModifiers()) {
1775 this->write("highp ");
1776 }
Brian Osmancc10d792018-07-20 13:09:45 -04001777 this->write("vec4 sk_FragCoord_Workaround;\n");
1778 break;
1779 }
1780 default:
1781 break;
1782 }
1783 }
1784
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001785 if (this->usesPrecisionModifiers()) {
1786 this->writeLine("precision mediump float;");
Brian Salomon67529b22019-08-13 15:31:04 -04001787 this->writeLine("precision mediump sampler2D;");
Brian Salomon5a5f3e82019-08-16 15:05:40 -04001788 if (fFoundExternalSamplerDecl &&
1789 !fProgram.fSettings.fCaps->noDefaultPrecisionForExternalSamplers()) {
Brian Salomon67529b22019-08-13 15:31:04 -04001790 this->writeLine("precision mediump samplerExternalOES;");
1791 }
1792 if (fFoundRectSamplerDecl) {
1793 this->writeLine("precision mediump sampler2DRect;");
1794 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001795 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001796 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001797 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001798 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001799}
1800
1801}