blob: 2a96e393e69996de1ccfac76303620e668bd44b6 [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 }
156 default:
157 return type.name();
158 }
159}
160
ethannicholasf789b382016-08-03 12:43:36 -0700161void GLSLCodeGenerator::writeType(const Type& type) {
162 if (type.kind() == Type::kStruct_Kind) {
163 for (const Type* search : fWrittenStructs) {
164 if (*search == type) {
165 // already written
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700166 this->write(type.fName);
ethannicholasf789b382016-08-03 12:43:36 -0700167 return;
168 }
169 }
170 fWrittenStructs.push_back(&type);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700171 this->write("struct ");
172 this->write(type.fName);
173 this->writeLine(" {");
ethannicholasf789b382016-08-03 12:43:36 -0700174 fIndentation++;
175 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700176 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400177 this->writeTypePrecision(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700178 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -0700179 this->writeType(*f.fType);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700180 this->write(" ");
181 this->write(f.fName);
182 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -0700183 }
184 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -0500185 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -0700186 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400187 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700188 }
189}
190
191void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
192 switch (expr.fKind) {
193 case Expression::kBinary_Kind:
194 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
195 break;
196 case Expression::kBoolLiteral_Kind:
197 this->writeBoolLiteral((BoolLiteral&) expr);
198 break;
199 case Expression::kConstructor_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400200 this->writeConstructor((Constructor&) expr, parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700201 break;
202 case Expression::kIntLiteral_Kind:
203 this->writeIntLiteral((IntLiteral&) expr);
204 break;
205 case Expression::kFieldAccess_Kind:
206 this->writeFieldAccess(((FieldAccess&) expr));
207 break;
208 case Expression::kFloatLiteral_Kind:
209 this->writeFloatLiteral(((FloatLiteral&) expr));
210 break;
211 case Expression::kFunctionCall_Kind:
212 this->writeFunctionCall((FunctionCall&) expr);
213 break;
214 case Expression::kPrefix_Kind:
215 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
216 break;
217 case Expression::kPostfix_Kind:
218 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
219 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400220 case Expression::kSetting_Kind:
221 this->writeSetting((Setting&) expr);
222 break;
ethannicholasf789b382016-08-03 12:43:36 -0700223 case Expression::kSwizzle_Kind:
224 this->writeSwizzle((Swizzle&) expr);
225 break;
226 case Expression::kVariableReference_Kind:
227 this->writeVariableReference((VariableReference&) expr);
228 break;
229 case Expression::kTernary_Kind:
230 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
231 break;
232 case Expression::kIndex_Kind:
233 this->writeIndexExpression((IndexExpression&) expr);
234 break;
235 default:
236 ABORT("unsupported expression: %s", expr.description().c_str());
237 }
238}
239
ethannicholas5961bc92016-10-12 06:39:56 -0700240static bool is_abs(Expression& expr) {
241 if (expr.fKind != Expression::kFunctionCall_Kind) {
242 return false;
243 }
244 return ((FunctionCall&) expr).fFunction.fName == "abs";
245}
246
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500247// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700248// Tegra3 compiler bug.
249void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400250 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400251 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
252 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400253 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.fType) +
254 this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
255 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.fType) +
256 this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700257 this->write("((" + tmpVar1 + " = ");
258 this->writeExpression(absExpr, kTopLevel_Precedence);
259 this->write(") < (" + tmpVar2 + " = ");
260 this->writeExpression(otherExpr, kAssignment_Precedence);
261 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
262}
263
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500264void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
265 this->write("(1.0 / sqrt(");
266 this->writeExpression(x, kTopLevel_Precedence);
267 this->write("))");
268}
269
270void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
271 String name;
272 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
273 name = "_determinant2";
274 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
275 fWrittenIntrinsics.insert(name);
276 fExtraFunctions.writeText((
277 "float " + name + "(mat2 m) {"
278 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
279 "}"
280 ).c_str());
281 }
282 }
283 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
284 name = "_determinant3";
285 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
286 fWrittenIntrinsics.insert(name);
287 fExtraFunctions.writeText((
288 "float " + name + "(mat3 m) {"
289 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
290 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
291 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
292 " float b01 = a22 * a11 - a12 * a21;"
293 " float b11 = -a22 * a10 + a12 * a20;"
294 " float b21 = a21 * a10 - a11 * a20;"
295 " return a00 * b01 + a01 * b11 + a02 * b21;"
296 "}"
297 ).c_str());
298 }
299 }
300 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
301 name = "_determinant3";
302 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
303 fWrittenIntrinsics.insert(name);
304 fExtraFunctions.writeText((
305 "mat4 " + name + "(mat4 m) {"
306 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
307 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
308 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
309 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
310 " float b00 = a00 * a11 - a01 * a10;"
311 " float b01 = a00 * a12 - a02 * a10;"
312 " float b02 = a00 * a13 - a03 * a10;"
313 " float b03 = a01 * a12 - a02 * a11;"
314 " float b04 = a01 * a13 - a03 * a11;"
315 " float b05 = a02 * a13 - a03 * a12;"
316 " float b06 = a20 * a31 - a21 * a30;"
317 " float b07 = a20 * a32 - a22 * a30;"
318 " float b08 = a20 * a33 - a23 * a30;"
319 " float b09 = a21 * a32 - a22 * a31;"
320 " float b10 = a21 * a33 - a23 * a31;"
321 " float b11 = a22 * a33 - a23 * a32;"
322 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
323 "}"
324 ).c_str());
325 }
326 }
327 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400328 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500329 }
330 this->write(name + "(");
331 this->writeExpression(mat, kTopLevel_Precedence);
332 this->write(")");
333}
334
335void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
336 String name;
337 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
338 name = "_inverse2";
339 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
340 fWrittenIntrinsics.insert(name);
341 fExtraFunctions.writeText((
342 "mat2 " + name + "(mat2 m) {"
343 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
344 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
345 "}"
346 ).c_str());
347 }
348 }
349 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
350 name = "_inverse3";
351 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
352 fWrittenIntrinsics.insert(name);
353 fExtraFunctions.writeText((
354 "mat3 " + name + "(mat3 m) {"
355 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
356 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
357 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
358 " float b01 = a22 * a11 - a12 * a21;"
359 " float b11 = -a22 * a10 + a12 * a20;"
360 " float b21 = a21 * a10 - a11 * a20;"
361 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
362 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
363 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
364 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
365 "}"
366 ).c_str());
367 }
368 }
369 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
370 name = "_inverse4";
371 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
372 fWrittenIntrinsics.insert(name);
373 fExtraFunctions.writeText((
374 "mat4 " + name + "(mat4 m) {"
375 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
376 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
377 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
378 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
379 " float b00 = a00 * a11 - a01 * a10;"
380 " float b01 = a00 * a12 - a02 * a10;"
381 " float b02 = a00 * a13 - a03 * a10;"
382 " float b03 = a01 * a12 - a02 * a11;"
383 " float b04 = a01 * a13 - a03 * a11;"
384 " float b05 = a02 * a13 - a03 * a12;"
385 " float b06 = a20 * a31 - a21 * a30;"
386 " float b07 = a20 * a32 - a22 * a30;"
387 " float b08 = a20 * a33 - a23 * a30;"
388 " float b09 = a21 * a32 - a22 * a31;"
389 " float b10 = a21 * a33 - a23 * a31;"
390 " float b11 = a22 * a33 - a23 * a32;"
391 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
392 " b04 * b07 + b05 * b06;"
393 " return mat4("
394 " a11 * b11 - a12 * b10 + a13 * b09,"
395 " a02 * b10 - a01 * b11 - a03 * b09,"
396 " a31 * b05 - a32 * b04 + a33 * b03,"
397 " a22 * b04 - a21 * b05 - a23 * b03,"
398 " a12 * b08 - a10 * b11 - a13 * b07,"
399 " a00 * b11 - a02 * b08 + a03 * b07,"
400 " a32 * b02 - a30 * b05 - a33 * b01,"
401 " a20 * b05 - a22 * b02 + a23 * b01,"
402 " a10 * b10 - a11 * b08 + a13 * b06,"
403 " a01 * b08 - a00 * b10 - a03 * b06,"
404 " a30 * b04 - a31 * b02 + a33 * b00,"
405 " a21 * b02 - a20 * b04 - a23 * b00,"
406 " a11 * b07 - a10 * b09 - a12 * b06,"
407 " a00 * b09 - a01 * b07 + a02 * b06,"
408 " a31 * b01 - a30 * b03 - a32 * b00,"
409 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
410 "}"
411 ).c_str());
412 }
413 }
414 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400415 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500416 }
417 this->write(name + "(");
418 this->writeExpression(mat, kTopLevel_Precedence);
419 this->write(")");
420}
421
422void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
423 String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
424 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
425 fWrittenIntrinsics.insert(name);
426 String type = this->getTypeName(mat.fType);
427 const Type& base = mat.fType.componentType();
428 String transposed = this->getTypeName(base.toCompound(fContext,
429 mat.fType.rows(),
430 mat.fType.columns()));
431 fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
432 transposed + "(").c_str());
433 const char* separator = "";
434 for (int row = 0; row < mat.fType.rows(); ++row) {
435 for (int column = 0; column < mat.fType.columns(); ++column) {
436 fExtraFunctions.writeText(separator);
437 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
438 "]").c_str());
439 separator = ", ";
440 }
441 }
442 fExtraFunctions.writeText("); }");
443 }
444 this->write(name + "(");
445 this->writeExpression(mat, kTopLevel_Precedence);
446 this->write(")");
447}
448
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400449std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
450 GLSLCodeGenerator::fFunctionClasses = nullptr;
451
ethannicholasf789b382016-08-03 12:43:36 -0700452void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400453#ifdef SKSL_STANDALONE
454 if (!fFunctionClasses) {
455#else
456 static SkOnce once;
457 once([] {
458#endif
459 fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
Adrienne Walker92b161f2018-08-22 10:41:52 -0700460 (*fFunctionClasses)["abs"] = FunctionClass::kAbs;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400461 (*fFunctionClasses)["atan"] = FunctionClass::kAtan;
462 (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700463 (*fFunctionClasses)["dFdx"] = FunctionClass::kDFdx;
464 (*fFunctionClasses)["dFdy"] = FunctionClass::kDFdy;
465 (*fFunctionClasses)["fwidth"] = FunctionClass::kFwidth;
Chris Daltona7086182018-11-16 09:33:43 -0500466 (*fFunctionClasses)["fma"] = FunctionClass::kFMA;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400467 (*fFunctionClasses)["fract"] = FunctionClass::kFract;
468 (*fFunctionClasses)["inverse"] = FunctionClass::kInverse;
469 (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
470 (*fFunctionClasses)["min"] = FunctionClass::kMin;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700471 (*fFunctionClasses)["pow"] = FunctionClass::kPow;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400472 (*fFunctionClasses)["saturate"] = FunctionClass::kSaturate;
Ethan Nicholas13863662019-07-29 13:05:15 -0400473 (*fFunctionClasses)["sample"] = FunctionClass::kTexture;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400474 (*fFunctionClasses)["transpose"] = FunctionClass::kTranspose;
ethannicholas5961bc92016-10-12 06:39:56 -0700475 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400476#ifndef SKSL_STANDALONE
477 );
478#endif
479 const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
480 fFunctionClasses->end();
Brian Osman8a83ca42018-02-12 14:32:17 -0500481 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400482 bool nameWritten = false;
483 if (found != fFunctionClasses->end()) {
484 switch (found->second) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700485 case FunctionClass::kAbs: {
486 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
487 break;
488 SkASSERT(c.fArguments.size() == 1);
489 if (c.fArguments[0]->fType != *fContext.fInt_Type)
490 break;
491 // abs(int) on Intel OSX is incorrect, so emulate it:
492 String name = "_absemulation";
493 this->write(name);
494 nameWritten = true;
495 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
496 fWrittenIntrinsics.insert(name);
497 fExtraFunctions.writeText((
498 "int " + name + "(int x) {\n"
499 " return x * sign(x);\n"
500 "}\n"
501 ).c_str());
502 }
503 break;
504 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400505 case FunctionClass::kAtan:
506 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
507 c.fArguments.size() == 2 &&
508 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
509 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
510 if (p.fOperator == Token::MINUS) {
511 this->write("atan(");
512 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
513 this->write(", -1.0 * ");
514 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
515 this->write(")");
516 return;
517 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500518 }
519 break;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700520 case FunctionClass::kDFdy:
521 if (fProgram.fSettings.fFlipY) {
522 // Flipping Y also negates the Y derivatives.
523 this->write("-dFdy");
524 nameWritten = true;
525 }
526 // fallthru
527 case FunctionClass::kDFdx:
528 case FunctionClass::kFwidth:
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400529 if (!fFoundDerivatives &&
530 fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
531 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
532 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
533 fFoundDerivatives = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500534 }
535 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400536 case FunctionClass::kDeterminant:
537 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
538 SkASSERT(c.fArguments.size() == 1);
539 this->writeDeterminantHack(*c.fArguments[0]);
540 return;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500541 }
542 break;
Chris Daltona7086182018-11-16 09:33:43 -0500543 case FunctionClass::kFMA:
544 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
545 SkASSERT(c.fArguments.size() == 3);
546 this->write("((");
547 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
548 this->write(") * (");
549 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
550 this->write(") + (");
551 this->writeExpression(*c.fArguments[2], kSequence_Precedence);
552 this->write("))");
553 return;
554 }
555 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400556 case FunctionClass::kFract:
557 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
558 SkASSERT(c.fArguments.size() == 1);
559 this->write("(0.5 - sign(");
560 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
561 this->write(") * (0.5 - fract(abs(");
562 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
563 this->write("))))");
564 return;
565 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500566 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400567 case FunctionClass::kInverse:
568 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
569 SkASSERT(c.fArguments.size() == 1);
570 this->writeInverseHack(*c.fArguments[0]);
571 return;
572 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500573 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400574 case FunctionClass::kInverseSqrt:
575 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
576 SkASSERT(c.fArguments.size() == 1);
577 this->writeInverseSqrtHack(*c.fArguments[0]);
578 return;
579 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500580 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400581 case FunctionClass::kMin:
582 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
583 SkASSERT(c.fArguments.size() == 2);
584 if (is_abs(*c.fArguments[0])) {
585 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
586 return;
587 }
588 if (is_abs(*c.fArguments[1])) {
589 // note that this violates the GLSL left-to-right evaluation semantics.
590 // I doubt it will ever end up mattering, but it's worth calling out.
591 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
592 return;
593 }
594 }
595 break;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700596 case FunctionClass::kPow:
597 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
598 break;
599 }
600 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
601 // constant. It's hard to tell what constitutes "constant" here
602 // so just replace in all cases.
603
604 // Change pow(x, y) into exp2(y * log2(x))
605 this->write("exp2(");
606 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
607 this->write(" * log2(");
608 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
609 this->write("))");
610 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400611 case FunctionClass::kSaturate:
612 SkASSERT(c.fArguments.size() == 1);
613 this->write("clamp(");
614 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
615 this->write(", 0.0, 1.0)");
616 return;
617 case FunctionClass::kTexture: {
618 const char* dim = "";
619 bool proj = false;
620 switch (c.fArguments[0]->fType.dimensions()) {
621 case SpvDim1D:
622 dim = "1D";
623 isTextureFunctionWithBias = true;
624 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
625 proj = false;
626 } else {
627 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
628 proj = true;
629 }
630 break;
631 case SpvDim2D:
632 dim = "2D";
633 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
634 isTextureFunctionWithBias = true;
635 }
636 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
637 proj = false;
638 } else {
639 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
640 proj = true;
641 }
642 break;
643 case SpvDim3D:
644 dim = "3D";
645 isTextureFunctionWithBias = true;
646 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
647 proj = false;
648 } else {
649 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
650 proj = true;
651 }
652 break;
653 case SpvDimCube:
654 dim = "Cube";
655 isTextureFunctionWithBias = true;
656 proj = false;
657 break;
658 case SpvDimRect:
Khushal Sagar2cb13152019-09-11 23:17:26 +0000659 dim = "2DRect";
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400660 proj = false;
661 break;
662 case SpvDimBuffer:
663 SkASSERT(false); // doesn't exist
664 dim = "Buffer";
665 proj = false;
666 break;
667 case SpvDimSubpassData:
668 SkASSERT(false); // doesn't exist
669 dim = "SubpassData";
670 proj = false;
671 break;
672 }
Ethan Nicholas13863662019-07-29 13:05:15 -0400673 if (fTextureFunctionOverride != "") {
674 this->write(fTextureFunctionOverride.c_str());
675 } else {
676 this->write("texture");
677 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
678 this->write(dim);
679 }
680 if (proj) {
681 this->write("Proj");
682 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400683 }
684 nameWritten = true;
685 break;
686 }
687 case FunctionClass::kTranspose:
688 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
689 SkASSERT(c.fArguments.size() == 1);
690 this->writeTransposeHack(*c.fArguments[0]);
691 return;
692 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500693 break;
694 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400695 }
696 if (!nameWritten) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500697 this->write(c.fFunction.fName);
698 }
699 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700700 const char* separator = "";
701 for (const auto& arg : c.fArguments) {
702 this->write(separator);
703 separator = ", ";
704 this->writeExpression(*arg, kSequence_Precedence);
705 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500706 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
707 this->write(", -0.5");
708 }
ethannicholasf789b382016-08-03 12:43:36 -0700709 this->write(")");
710}
711
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400712void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
713 if (c.fArguments.size() == 1 &&
Ethan Nicholase1f55022019-02-05 17:17:40 -0500714 (this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType) ||
715 (c.fType.kind() == Type::kScalar_Kind &&
716 c.fArguments[0]->fType == *fContext.fFloatLiteral_Type))) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400717 // in cases like half(float), they're different types as far as SkSL is concerned but the
718 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
719 // out the inner expression here.
720 this->writeExpression(*c.fArguments[0], parentPrecedence);
721 return;
722 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400723 this->writeType(c.fType);
724 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700725 const char* separator = "";
726 for (const auto& arg : c.fArguments) {
727 this->write(separator);
728 separator = ", ";
729 this->writeExpression(*arg, kSequence_Precedence);
730 }
731 this->write(")");
732}
733
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500734void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000735 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500736 if (!fSetupFragCoordWorkaround) {
737 const char* precision = usesPrecisionModifiers() ? "highp " : "";
738 fFunctionHeader += precision;
739 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
740 fFunctionHeader += precision;
741 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
742 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
743 // Ensure that we get exact .5 values for x and y.
744 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
745 "vec2(.5);\n";
746 fSetupFragCoordWorkaround = true;
747 }
748 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000749 return;
750 }
751
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500752 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
753 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
754 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
755 if (!fProgram.fSettings.fFlipY) {
756 this->write("gl_FragCoord");
757 } else if (const char* extension =
Ethan Nicholascd700e92018-08-24 16:43:57 -0400758 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500759 if (!fSetupFragPositionGlobal) {
760 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400761 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500762 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400763 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500764 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000765 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500766 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000767 } else {
Ethan Nicholascd700e92018-08-24 16:43:57 -0400768 if (!fSetupFragPositionLocal) {
Michael Ludwig5e1f6ea2018-12-03 15:14:50 -0500769 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
Michael Ludwigf0b60442018-12-10 14:43:38 +0000770 fFunctionHeader += " vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
771 " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500772 fSetupFragPositionLocal = true;
773 }
774 this->write("sk_FragCoord");
775 }
776}
777
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500778void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
779 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
780 case SK_FRAGCOLOR_BUILTIN:
781 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
782 this->write("sk_FragColor");
783 } else {
784 this->write("gl_FragColor");
785 }
786 break;
787 case SK_FRAGCOORD_BUILTIN:
788 this->writeFragCoord();
789 break;
Ethan Nicholascd700e92018-08-24 16:43:57 -0400790 case SK_WIDTH_BUILTIN:
791 this->write("u_skRTWidth");
792 break;
793 case SK_HEIGHT_BUILTIN:
794 this->write("u_skRTHeight");
795 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600796 case SK_CLOCKWISE_BUILTIN:
Chris Daltonc8ece3d2018-07-30 15:03:45 -0600797 this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
Chris Dalton49d14e92018-07-27 12:38:35 -0600798 break;
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600799 case SK_SAMPLEMASK_BUILTIN:
800 SkASSERT(fProgram.fSettings.fCaps->sampleVariablesSupport() ||
801 fProgram.fSettings.fCaps->sampleVariablesStencilSupport());
802 this->write("gl_SampleMask");
803 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500804 case SK_VERTEXID_BUILTIN:
805 this->write("gl_VertexID");
806 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600807 case SK_INSTANCEID_BUILTIN:
808 this->write("gl_InstanceID");
809 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500810 case SK_CLIPDISTANCE_BUILTIN:
811 this->write("gl_ClipDistance");
812 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500813 case SK_IN_BUILTIN:
814 this->write("gl_in");
815 break;
816 case SK_INVOCATIONID_BUILTIN:
817 this->write("gl_InvocationID");
818 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400819 case SK_LASTFRAGCOLOR_BUILTIN:
820 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
821 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500822 default:
823 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700824 }
ethannicholasf789b382016-08-03 12:43:36 -0700825}
826
827void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
828 this->writeExpression(*expr.fBase, kPostfix_Precedence);
829 this->write("[");
830 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
831 this->write("]");
832}
833
Brian Osmancd3261a2018-01-16 13:52:29 +0000834bool is_sk_position(const FieldAccess& f) {
835 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
836}
837
ethannicholasf789b382016-08-03 12:43:36 -0700838void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
839 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
840 this->writeExpression(*f.fBase, kPostfix_Precedence);
841 this->write(".");
842 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500843 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
844 case SK_CLIPDISTANCE_BUILTIN:
845 this->write("gl_ClipDistance");
846 break;
847 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400848 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
849 if (name == "sk_Position") {
850 this->write("gl_Position");
851 } else if (name == "sk_PointSize") {
852 this->write("gl_PointSize");
853 } else {
854 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
855 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500856 }
ethannicholasf789b382016-08-03 12:43:36 -0700857}
858
Ethan Nicholase455f652019-09-13 12:52:55 -0400859void GLSLCodeGenerator::writeConstantSwizzle(const Swizzle& swizzle, const String& constants) {
860 this->writeType(swizzle.fType);
861 this->write("(");
862 this->write(constants);
863 this->write(")");
864}
865
866void GLSLCodeGenerator::writeSwizzleMask(const Swizzle& swizzle, const String& mask) {
ethannicholasf789b382016-08-03 12:43:36 -0700867 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
868 this->write(".");
Ethan Nicholase455f652019-09-13 12:52:55 -0400869 this->write(mask);
870}
871
872void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
873 const String& mask,
874 GLSLCodeGenerator::SwizzleOrder order) {
875 this->writeType(swizzle.fType);
876 this->write("(");
877 if (order == SwizzleOrder::CONSTANTS_FIRST) {
878 this->write(constants);
879 this->write(", ");
880 this->writeSwizzleMask(swizzle, mask);
881 } else {
882 this->writeSwizzleMask(swizzle, mask);
883 this->write(", ");
884 this->write(constants);
885 }
886 this->write(")");
887}
888
889void GLSLCodeGenerator::writeSwizzleConstructor(const Swizzle& swizzle, const String& constants,
890 const String& mask, const String& reswizzle) {
891 this->writeSwizzleConstructor(swizzle, constants, mask, SwizzleOrder::MASK_FIRST);
892 this->write(".");
893 this->write(reswizzle);
894}
895
896// Writing a swizzle is complicated due to the handling of constant swizzle components. The most
897// problematic case is a mask like '.r00a'. A naive approach might turn that into
898// 'vec4(base.r, 0, 0, base.a)', but that would cause 'base' to be evaluated twice. We instead
899// group the swizzle mask ('ra') and constants ('0, 0') together and use a secondary swizzle to put
900// them back into the right order, so in this case we end up with something like
901// 'vec4(base4.ra, 0, 0).rbag'.
902void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
903 // has a 1 bit in every position for which the swizzle mask is a constant, so 'r0b1' would
904 // yield binary 0101.
905 int constantBits = 0;
906 String mask;
907 String constants;
908 // compute mask ("ra") and constant ("0, 0") strings, and fill in constantBits
ethannicholasf789b382016-08-03 12:43:36 -0700909 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -0400910 constantBits <<= 1;
911 switch (c) {
912 case SKSL_SWIZZLE_0:
913 constantBits |= 1;
914 if (constants.length() > 0) {
915 constants += ", ";
916 }
917 constants += "0";
918 break;
919 case SKSL_SWIZZLE_1:
920 constantBits |= 1;
921 if (constants.length() > 0) {
922 constants += ", ";
923 }
924 constants += "1";
925 break;
926 case 0:
927 mask += "x";
928 break;
929 case 1:
930 mask += "y";
931 break;
932 case 2:
933 mask += "z";
934 break;
935 case 3:
936 mask += "w";
937 break;
938 default:
939 SkASSERT(false);
Ethan Nicholasac285b12019-02-12 16:05:18 -0500940 }
941 }
Ethan Nicholase455f652019-09-13 12:52:55 -0400942 switch (swizzle.fComponents.size()) {
943 case 1:
944 if (constantBits == 1) {
945 this->write(constants);
946 }
947 else {
948 this->writeSwizzleMask(swizzle, mask);
949 }
950 break;
951 case 2:
952 switch (constantBits) {
953 case 0: // 00
954 this->writeSwizzleMask(swizzle, mask);
955 break;
956 case 1: // 01
957 this->writeSwizzleConstructor(swizzle, constants, mask,
958 SwizzleOrder::MASK_FIRST);
959 break;
960 case 2: // 10
961 this->writeSwizzleConstructor(swizzle, constants, mask,
962 SwizzleOrder::CONSTANTS_FIRST);
963 break;
964 case 3: // 11
965 this->writeConstantSwizzle(swizzle, constants);
966 break;
967 default:
968 SkASSERT(false);
969 }
970 break;
971 case 3:
972 switch (constantBits) {
973 case 0: // 000
974 this->writeSwizzleMask(swizzle, mask);
975 break;
976 case 1: // 001
977 case 3: // 011
978 this->writeSwizzleConstructor(swizzle, constants, mask,
979 SwizzleOrder::MASK_FIRST);
980 break;
981 case 4: // 100
982 case 6: // 110
983 this->writeSwizzleConstructor(swizzle, constants, mask,
984 SwizzleOrder::CONSTANTS_FIRST);
985 break;
986 case 2: // 010
987 this->writeSwizzleConstructor(swizzle, constants, mask, "xzy");
988 break;
989 case 5: // 101
990 this->writeSwizzleConstructor(swizzle, constants, mask, "yxz");
991 break;
992 case 7: // 111
993 this->writeConstantSwizzle(swizzle, constants);
994 break;
995 }
996 break;
997 case 4:
998 switch (constantBits) {
999 case 0: // 0000
1000 this->writeSwizzleMask(swizzle, mask);
1001 break;
1002 case 1: // 0001
1003 case 3: // 0011
1004 case 7: // 0111
1005 this->writeSwizzleConstructor(swizzle, constants, mask,
1006 SwizzleOrder::MASK_FIRST);
1007 break;
1008 case 8: // 1000
1009 case 12: // 1100
1010 case 14: // 1110
1011 this->writeSwizzleConstructor(swizzle, constants, mask,
1012 SwizzleOrder::CONSTANTS_FIRST);
1013 break;
1014 case 2: // 0010
1015 this->writeSwizzleConstructor(swizzle, constants, mask, "xywz");
1016 break;
1017 case 4: // 0100
1018 this->writeSwizzleConstructor(swizzle, constants, mask, "xwyz");
1019 break;
1020 case 5: // 0101
1021 this->writeSwizzleConstructor(swizzle, constants, mask, "xzyw");
1022 break;
1023 case 6: // 0110
1024 this->writeSwizzleConstructor(swizzle, constants, mask, "xzwy");
1025 break;
1026 case 9: // 1001
1027 this->writeSwizzleConstructor(swizzle, constants, mask, "zxyw");
1028 break;
1029 case 10: // 1010
1030 this->writeSwizzleConstructor(swizzle, constants, mask, "zxwy");
1031 break;
1032 case 11: // 1011
1033 this->writeSwizzleConstructor(swizzle, constants, mask, "yxzw");
1034 break;
1035 case 13: // 1101
1036 this->writeSwizzleConstructor(swizzle, constants, mask, "yzxw");
1037 break;
1038 case 15: // 1111
1039 this->writeConstantSwizzle(swizzle, constants);
1040 break;
1041 }
ethannicholasf789b382016-08-03 12:43:36 -07001042 }
1043}
1044
Ethan Nicholas762466e2017-06-29 10:03:38 -04001045GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -07001046 switch (op) {
1047 case Token::STAR: // fall through
1048 case Token::SLASH: // fall through
1049 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
1050 case Token::PLUS: // fall through
1051 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
1052 case Token::SHL: // fall through
1053 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
1054 case Token::LT: // fall through
1055 case Token::GT: // fall through
1056 case Token::LTEQ: // fall through
1057 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
1058 case Token::EQEQ: // fall through
1059 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
1060 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
1061 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
1062 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
1063 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
1064 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
1065 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
1066 case Token::EQ: // fall through
1067 case Token::PLUSEQ: // fall through
1068 case Token::MINUSEQ: // fall through
1069 case Token::STAREQ: // fall through
1070 case Token::SLASHEQ: // fall through
1071 case Token::PERCENTEQ: // fall through
1072 case Token::SHLEQ: // fall through
1073 case Token::SHREQ: // fall through
1074 case Token::LOGICALANDEQ: // fall through
1075 case Token::LOGICALXOREQ: // fall through
1076 case Token::LOGICALOREQ: // fall through
1077 case Token::BITWISEANDEQ: // fall through
1078 case Token::BITWISEXOREQ: // fall through
1079 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001080 case Token::COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -07001081 default: ABORT("unsupported binary operator");
1082 }
1083}
1084
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001085void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -07001086 Precedence parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001087 if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
1088 (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
1089 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
1090 return;
1091 }
1092
Ethan Nicholas762466e2017-06-29 10:03:38 -04001093 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -07001094 if (precedence >= parentPrecedence) {
1095 this->write("(");
1096 }
Ethan Nicholas0b631962018-07-24 13:41:11 -04001097 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
1098 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +00001099 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
1100 is_sk_position((FieldAccess&) *b.fLeft) &&
1101 !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
1102 !fProgram.fSettings.fCaps->canUseFragCoord();
1103 if (positionWorkaround) {
1104 this->write("sk_FragCoord_Workaround = (");
1105 }
ethannicholasf789b382016-08-03 12:43:36 -07001106 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001107 this->write(" ");
1108 this->write(Compiler::OperatorName(b.fOperator));
1109 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -07001110 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +00001111 if (positionWorkaround) {
1112 this->write(")");
1113 }
ethannicholasf789b382016-08-03 12:43:36 -07001114 if (precedence >= parentPrecedence) {
1115 this->write(")");
1116 }
1117}
1118
Adrienne Walkerc02165f2018-08-21 11:08:11 -07001119void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
1120 Precedence parentPrecedence) {
1121 if (kTernary_Precedence >= parentPrecedence) {
1122 this->write("(");
1123 }
1124
1125 // Transform:
1126 // a && b => a ? b : false
1127 // a || b => a ? true : b
1128 this->writeExpression(*b.fLeft, kTernary_Precedence);
1129 this->write(" ? ");
1130 if (b.fOperator == Token::LOGICALAND) {
1131 this->writeExpression(*b.fRight, kTernary_Precedence);
1132 } else {
1133 BoolLiteral boolTrue(fContext, -1, true);
1134 this->writeBoolLiteral(boolTrue);
1135 }
1136 this->write(" : ");
1137 if (b.fOperator == Token::LOGICALAND) {
1138 BoolLiteral boolFalse(fContext, -1, false);
1139 this->writeBoolLiteral(boolFalse);
1140 } else {
1141 this->writeExpression(*b.fRight, kTernary_Precedence);
1142 }
1143 if (kTernary_Precedence >= parentPrecedence) {
1144 this->write(")");
1145 }
1146}
1147
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001148void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -07001149 Precedence parentPrecedence) {
1150 if (kTernary_Precedence >= parentPrecedence) {
1151 this->write("(");
1152 }
1153 this->writeExpression(*t.fTest, kTernary_Precedence);
1154 this->write(" ? ");
1155 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
1156 this->write(" : ");
1157 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
1158 if (kTernary_Precedence >= parentPrecedence) {
1159 this->write(")");
1160 }
1161}
1162
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001163void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001164 Precedence parentPrecedence) {
1165 if (kPrefix_Precedence >= parentPrecedence) {
1166 this->write("(");
1167 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001168 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001169 this->writeExpression(*p.fOperand, kPrefix_Precedence);
1170 if (kPrefix_Precedence >= parentPrecedence) {
1171 this->write(")");
1172 }
1173}
1174
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001175void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001176 Precedence parentPrecedence) {
1177 if (kPostfix_Precedence >= parentPrecedence) {
1178 this->write("(");
1179 }
1180 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001181 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001182 if (kPostfix_Precedence >= parentPrecedence) {
1183 this->write(")");
1184 }
1185}
1186
1187void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1188 this->write(b.fValue ? "true" : "false");
1189}
1190
1191void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -07001192 if (i.fType == *fContext.fUInt_Type) {
1193 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -05001194 } else if (i.fType == *fContext.fUShort_Type) {
1195 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001196 } else if (i.fType == *fContext.fUByte_Type) {
1197 this->write(to_string(i.fValue & 0xff) + "u");
1198 } else {
ethannicholas5961bc92016-10-12 06:39:56 -07001199 this->write(to_string((int32_t) i.fValue));
1200 }
ethannicholasf789b382016-08-03 12:43:36 -07001201}
1202
1203void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1204 this->write(to_string(f.fValue));
1205}
1206
Ethan Nicholas762466e2017-06-29 10:03:38 -04001207void GLSLCodeGenerator::writeSetting(const Setting& s) {
1208 ABORT("internal error; setting was not folded to a constant during compilation\n");
1209}
1210
ethannicholasf789b382016-08-03 12:43:36 -07001211void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholasc6dce5a2019-07-24 16:51:36 -04001212 fSetupFragPositionLocal = false;
1213 fSetupFragCoordWorkaround = false;
Ethan Nicholas00543112018-07-31 09:44:36 -04001214 if (fProgramKind != Program::kPipelineStage_Kind) {
1215 this->writeTypePrecision(f.fDeclaration.fReturnType);
1216 this->writeType(f.fDeclaration.fReturnType);
1217 this->write(" " + f.fDeclaration.fName + "(");
1218 const char* separator = "";
1219 for (const auto& param : f.fDeclaration.fParameters) {
1220 this->write(separator);
1221 separator = ", ";
1222 this->writeModifiers(param->fModifiers, false);
1223 std::vector<int> sizes;
1224 const Type* type = &param->fType;
1225 while (type->kind() == Type::kArray_Kind) {
1226 sizes.push_back(type->columns());
1227 type = &type->componentType();
1228 }
1229 this->writeTypePrecision(*type);
1230 this->writeType(*type);
1231 this->write(" " + param->fName);
1232 for (int s : sizes) {
1233 if (s <= 0) {
1234 this->write("[]");
1235 } else {
1236 this->write("[" + to_string(s) + "]");
1237 }
ethannicholas5961bc92016-10-12 06:39:56 -07001238 }
1239 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001240 this->writeLine(") {");
1241 fIndentation++;
ethannicholasf789b382016-08-03 12:43:36 -07001242 }
ethannicholas5961bc92016-10-12 06:39:56 -07001243 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001244 OutputStream* oldOut = fOut;
1245 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001246 fOut = &buffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04001247 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas00543112018-07-31 09:44:36 -04001248 if (fProgramKind != Program::kPipelineStage_Kind) {
1249 fIndentation--;
1250 this->writeLine("}");
1251 }
ethannicholas5961bc92016-10-12 06:39:56 -07001252
1253 fOut = oldOut;
1254 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001255 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001256}
1257
Greg Daniel64773e62016-11-22 09:44:03 -05001258void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001259 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001260 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1261 this->write("flat ");
1262 }
ethannicholas5961bc92016-10-12 06:39:56 -07001263 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1264 this->write("noperspective ");
1265 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001266 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001267 if (layout.size()) {
1268 this->write(layout + " ");
1269 }
Brian Salomonf9f45122016-11-29 11:59:17 -05001270 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1271 this->write("readonly ");
1272 }
1273 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1274 this->write("writeonly ");
1275 }
1276 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1277 this->write("coherent ");
1278 }
1279 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1280 this->write("volatile ");
1281 }
1282 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1283 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -07001284 }
Greg Daniel64773e62016-11-22 09:44:03 -05001285 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001286 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1287 this->write("inout ");
1288 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001289 if (globalContext &&
1290 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001291 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1292 : "varying ");
1293 } else {
1294 this->write("in ");
1295 }
1296 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001297 if (globalContext &&
1298 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001299 this->write("varying ");
1300 } else {
1301 this->write("out ");
1302 }
1303 }
1304 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1305 this->write("uniform ");
1306 }
1307 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1308 this->write("const ");
1309 }
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001310 if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1311 this->write("__pixel_localEXT ");
1312 }
1313 if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1314 this->write("__pixel_local_inEXT ");
1315 }
1316 if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1317 this->write("__pixel_local_outEXT ");
1318 }
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001319 switch (modifiers.fLayout.fFormat) {
1320 case Layout::Format::kUnspecified:
1321 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001322 case Layout::Format::kRGBA32F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001323 case Layout::Format::kR32F:
ethannicholas5961bc92016-10-12 06:39:56 -07001324 this->write("highp ");
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001325 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001326 case Layout::Format::kRGBA16F: // fall through
1327 case Layout::Format::kR16F: // fall through
1328 case Layout::Format::kLUMINANCE16F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001329 case Layout::Format::kRG16F:
1330 this->write("mediump ");
1331 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001332 case Layout::Format::kRGBA8: // fall through
1333 case Layout::Format::kR8: // fall through
1334 case Layout::Format::kRGBA8I: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001335 case Layout::Format::kR8I:
1336 this->write("lowp ");
1337 break;
ethannicholas5961bc92016-10-12 06:39:56 -07001338 }
ethannicholasf789b382016-08-03 12:43:36 -07001339}
1340
1341void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001342 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001343 return;
1344 }
ethannicholas5961bc92016-10-12 06:39:56 -07001345 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001346 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001347 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001348 const Type* structType = &intf.fVariable.fType;
1349 while (structType->kind() == Type::kArray_Kind) {
1350 structType = &structType->componentType();
1351 }
1352 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001353 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001354 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001355 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001356 this->writeLine(" " + f.fName + ";");
1357 }
1358 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001359 this->write("}");
1360 if (intf.fInstanceName.size()) {
1361 this->write(" ");
1362 this->write(intf.fInstanceName);
1363 for (const auto& size : intf.fSizes) {
1364 this->write("[");
1365 if (size) {
1366 this->writeExpression(*size, kTopLevel_Precedence);
1367 }
1368 this->write("]");
1369 }
1370 }
1371 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001372}
1373
Ethan Nicholas762466e2017-06-29 10:03:38 -04001374void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1375 this->writeExpression(value, kTopLevel_Precedence);
1376}
1377
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001378const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1379 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001380 switch (type.kind()) {
1381 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001382 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1383 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001384 if (fProgram.fSettings.fForceHighPrecision ||
1385 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1386 return "highp ";
1387 }
1388 return "mediump ";
1389 }
1390 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001391 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001392 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001393 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1394 type == *fContext.fUInt_Type) {
1395 return "highp ";
1396 }
1397 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001398 case Type::kVector_Kind: // fall through
1399 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001400 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001401 default:
1402 break;
1403 }
1404 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001405 return "";
1406}
1407
1408void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1409 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001410}
1411
ethannicholas5961bc92016-10-12 06:39:56 -07001412void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001413 if (!decl.fVars.size()) {
1414 return;
1415 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001416 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001417 for (const auto& stmt : decl.fVars) {
1418 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001419 if (wroteType) {
1420 this->write(", ");
1421 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001422 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001423 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001424 this->writeType(decl.fBaseType);
1425 this->write(" ");
1426 wroteType = true;
1427 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001428 this->write(var.fVar->fName);
1429 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001430 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001431 if (size) {
1432 this->writeExpression(*size, kTopLevel_Precedence);
1433 }
ethannicholasf789b382016-08-03 12:43:36 -07001434 this->write("]");
1435 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001436 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001437 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001438 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001439 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001440 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1441 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001442 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001443 }
Brian Osman061020e2018-04-17 14:22:15 -04001444 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001445 this->writeExtension(
1446 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001447 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001448 fFoundExternalSamplerDecl = true;
1449 }
Brian Salomon67529b22019-08-13 15:31:04 -04001450 if (!fFoundRectSamplerDecl && var.fVar->fType == *fContext.fSampler2DRect_Type) {
1451 fFoundRectSamplerDecl = true;
1452 }
ethannicholasf789b382016-08-03 12:43:36 -07001453 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001454 if (wroteType) {
1455 this->write(";");
1456 }
ethannicholasf789b382016-08-03 12:43:36 -07001457}
1458
1459void GLSLCodeGenerator::writeStatement(const Statement& s) {
1460 switch (s.fKind) {
1461 case Statement::kBlock_Kind:
1462 this->writeBlock((Block&) s);
1463 break;
1464 case Statement::kExpression_Kind:
1465 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1466 this->write(";");
1467 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001468 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001469 this->writeReturnStatement((ReturnStatement&) s);
1470 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001471 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001472 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001473 break;
1474 case Statement::kIf_Kind:
1475 this->writeIfStatement((IfStatement&) s);
1476 break;
1477 case Statement::kFor_Kind:
1478 this->writeForStatement((ForStatement&) s);
1479 break;
1480 case Statement::kWhile_Kind:
1481 this->writeWhileStatement((WhileStatement&) s);
1482 break;
1483 case Statement::kDo_Kind:
1484 this->writeDoStatement((DoStatement&) s);
1485 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001486 case Statement::kSwitch_Kind:
1487 this->writeSwitchStatement((SwitchStatement&) s);
1488 break;
ethannicholasf789b382016-08-03 12:43:36 -07001489 case Statement::kBreak_Kind:
1490 this->write("break;");
1491 break;
1492 case Statement::kContinue_Kind:
1493 this->write("continue;");
1494 break;
1495 case Statement::kDiscard_Kind:
1496 this->write("discard;");
1497 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001498 case Statement::kNop_Kind:
1499 this->write(";");
1500 break;
ethannicholasf789b382016-08-03 12:43:36 -07001501 default:
1502 ABORT("unsupported statement: %s", s.description().c_str());
1503 }
1504}
1505
Ethan Nicholascb670962017-04-20 19:31:52 -04001506void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1507 for (const auto& s : statements) {
1508 if (!s->isEmpty()) {
1509 this->writeStatement(*s);
1510 this->writeLine();
1511 }
1512 }
1513}
1514
ethannicholasf789b382016-08-03 12:43:36 -07001515void GLSLCodeGenerator::writeBlock(const Block& b) {
1516 this->writeLine("{");
1517 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001518 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001519 fIndentation--;
1520 this->write("}");
1521}
1522
1523void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1524 this->write("if (");
1525 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1526 this->write(") ");
1527 this->writeStatement(*stmt.fIfTrue);
1528 if (stmt.fIfFalse) {
1529 this->write(" else ");
1530 this->writeStatement(*stmt.fIfFalse);
1531 }
1532}
1533
1534void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1535 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001536 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001537 this->writeStatement(*f.fInitializer);
1538 } else {
1539 this->write("; ");
1540 }
1541 if (f.fTest) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001542 if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1543 std::unique_ptr<Expression> and_true(new BinaryExpression(
1544 -1, f.fTest->clone(), Token::LOGICALAND,
1545 std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1546 true)),
1547 *fContext.fBool_Type));
1548 this->writeExpression(*and_true, kTopLevel_Precedence);
1549 } else {
1550 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1551 }
ethannicholasf789b382016-08-03 12:43:36 -07001552 }
1553 this->write("; ");
1554 if (f.fNext) {
1555 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1556 }
1557 this->write(") ");
1558 this->writeStatement(*f.fStatement);
1559}
1560
1561void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1562 this->write("while (");
1563 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1564 this->write(") ");
1565 this->writeStatement(*w.fStatement);
1566}
1567
1568void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001569 if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1570 this->write("do ");
1571 this->writeStatement(*d.fStatement);
1572 this->write(" while (");
1573 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1574 this->write(");");
1575 return;
1576 }
1577
1578 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1579 // do {
1580 // CODE;
1581 // } while (CONDITION)
1582 //
1583 // to loops of the form
1584 // bool temp = false;
1585 // while (true) {
1586 // if (temp) {
1587 // if (!CONDITION) {
1588 // break;
1589 // }
1590 // }
1591 // temp = true;
1592 // CODE;
1593 // }
1594 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1595 this->write("bool ");
1596 this->write(tmpVar);
1597 this->writeLine(" = false;");
1598 this->writeLine("while (true) {");
1599 fIndentation++;
1600 this->write("if (");
1601 this->write(tmpVar);
1602 this->writeLine(") {");
1603 fIndentation++;
1604 this->write("if (!");
1605 this->writeExpression(*d.fTest, kPrefix_Precedence);
1606 this->writeLine(") {");
1607 fIndentation++;
1608 this->writeLine("break;");
1609 fIndentation--;
1610 this->writeLine("}");
1611 fIndentation--;
1612 this->writeLine("}");
1613 this->write(tmpVar);
1614 this->writeLine(" = true;");
ethannicholasf789b382016-08-03 12:43:36 -07001615 this->writeStatement(*d.fStatement);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001616 this->writeLine();
1617 fIndentation--;
1618 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001619}
1620
Ethan Nicholasaf197692017-02-27 13:26:45 -05001621void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1622 this->write("switch (");
1623 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1624 this->writeLine(") {");
1625 fIndentation++;
1626 for (const auto& c : s.fCases) {
1627 if (c->fValue) {
1628 this->write("case ");
1629 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1630 this->writeLine(":");
1631 } else {
1632 this->writeLine("default:");
1633 }
1634 fIndentation++;
1635 for (const auto& stmt : c->fStatements) {
1636 this->writeStatement(*stmt);
1637 this->writeLine();
1638 }
1639 fIndentation--;
1640 }
1641 fIndentation--;
1642 this->write("}");
1643}
1644
ethannicholasf789b382016-08-03 12:43:36 -07001645void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1646 this->write("return");
1647 if (r.fExpression) {
1648 this->write(" ");
1649 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1650 }
1651 this->write(";");
1652}
1653
Ethan Nicholas762466e2017-06-29 10:03:38 -04001654void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001655 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001656 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001657}
1658
Ethan Nicholas762466e2017-06-29 10:03:38 -04001659void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1660 switch (e.fKind) {
1661 case ProgramElement::kExtension_Kind:
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001662 this->writeExtension(((Extension&) e).fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001663 break;
1664 case ProgramElement::kVar_Kind: {
1665 VarDeclarations& decl = (VarDeclarations&) e;
1666 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001667 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001668 if (builtin == -1) {
1669 // normal var
1670 this->writeVarDeclarations(decl, true);
1671 this->writeLine();
1672 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001673 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
1674 ((VarDeclaration&) *decl.fVars[0]).fVar->fWriteCount) {
Brian Salomondc092132018-04-04 10:14:16 -04001675 if (fProgram.fSettings.fFragColorIsInOut) {
1676 this->write("inout ");
1677 } else {
1678 this->write("out ");
1679 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001680 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001681 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001682 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001683 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001684 }
Mike Klein5ce39722017-06-27 22:52:03 +00001685 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001686 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001687 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001688 case ProgramElement::kInterfaceBlock_Kind:
1689 this->writeInterfaceBlock((InterfaceBlock&) e);
1690 break;
1691 case ProgramElement::kFunction_Kind:
1692 this->writeFunction((FunctionDefinition&) e);
1693 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001694 case ProgramElement::kModifiers_Kind: {
1695 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1696 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1697 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001698 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001699 }
1700 fFoundGSInvocations = true;
1701 }
1702 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001703 this->writeLine(";");
1704 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001705 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001706 case ProgramElement::kEnum_Kind:
1707 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001708 default:
1709 printf("%s\n", e.description().c_str());
1710 ABORT("unsupported program element");
Ethan Nicholasc0709392017-06-27 11:20:22 -04001711 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001712}
1713
Ethan Nicholascd700e92018-08-24 16:43:57 -04001714void GLSLCodeGenerator::writeInputVars() {
1715 if (fProgram.fInputs.fRTWidth) {
1716 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1717 fGlobals.writeText("uniform ");
1718 fGlobals.writeText(precision);
1719 fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1720 }
1721 if (fProgram.fInputs.fRTHeight) {
1722 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1723 fGlobals.writeText("uniform ");
1724 fGlobals.writeText(precision);
1725 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1726 }
1727}
1728
Ethan Nicholas762466e2017-06-29 10:03:38 -04001729bool GLSLCodeGenerator::generateCode() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001730 if (fProgramKind != Program::kPipelineStage_Kind) {
1731 this->writeHeader();
1732 }
Chris Dalton8fd79552018-01-11 00:46:14 -05001733 if (Program::kGeometry_Kind == fProgramKind &&
1734 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001735 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001736 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001737 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001738 StringStream body;
1739 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001740 for (const auto& e : fProgram) {
1741 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001742 }
1743 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001744
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001745 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001746 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001747 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001748
1749 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1750 Layout layout;
1751 switch (fProgram.fKind) {
1752 case Program::kVertex_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001753 Modifiers modifiers(layout, Modifiers::kOut_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001754 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001755 if (this->usesPrecisionModifiers()) {
1756 this->write("highp ");
1757 }
Brian Osmancc10d792018-07-20 13:09:45 -04001758 this->write("vec4 sk_FragCoord_Workaround;\n");
1759 break;
1760 }
1761 case Program::kFragment_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001762 Modifiers modifiers(layout, Modifiers::kIn_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001763 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001764 if (this->usesPrecisionModifiers()) {
1765 this->write("highp ");
1766 }
Brian Osmancc10d792018-07-20 13:09:45 -04001767 this->write("vec4 sk_FragCoord_Workaround;\n");
1768 break;
1769 }
1770 default:
1771 break;
1772 }
1773 }
1774
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001775 if (this->usesPrecisionModifiers()) {
1776 this->writeLine("precision mediump float;");
Brian Salomon67529b22019-08-13 15:31:04 -04001777 this->writeLine("precision mediump sampler2D;");
Brian Salomon5a5f3e82019-08-16 15:05:40 -04001778 if (fFoundExternalSamplerDecl &&
1779 !fProgram.fSettings.fCaps->noDefaultPrecisionForExternalSamplers()) {
Brian Salomon67529b22019-08-13 15:31:04 -04001780 this->writeLine("precision mediump samplerExternalOES;");
1781 }
1782 if (fFoundRectSamplerDecl) {
1783 this->writeLine("precision mediump sampler2DRect;");
1784 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001785 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001786 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001787 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001788 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001789}
1790
1791}