blob: f44620430a73c0a9c973b93d63f4c8ae168f36eb [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
ethannicholasf789b382016-08-03 12:43:36 -07008#include "SkSLGLSLCodeGenerator.h"
9
Ethan Nicholas941e7e22016-12-12 15:33:30 -050010#include "SkSLCompiler.h"
ethannicholasf789b382016-08-03 12:43:36 -070011#include "ir/SkSLExpressionStatement.h"
12#include "ir/SkSLExtension.h"
13#include "ir/SkSLIndexExpression.h"
ethannicholas5961bc92016-10-12 06:39:56 -070014#include "ir/SkSLModifiersDeclaration.h"
Ethan Nicholascb670962017-04-20 19:31:52 -040015#include "ir/SkSLNop.h"
ethannicholasf789b382016-08-03 12:43:36 -070016#include "ir/SkSLVariableReference.h"
17
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040018#ifndef SKSL_STANDALONE
19#include "SkOnce.h"
20#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 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040093 else if (component == *fContext.fInt_Type ||
94 component == *fContext.fShort_Type ||
95 component == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040096 result = "ivec";
97 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040098 else if (component == *fContext.fUInt_Type ||
99 component == *fContext.fUShort_Type ||
100 component == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400101 result = "uvec";
102 }
103 else if (component == *fContext.fBool_Type) {
104 result = "bvec";
105 }
106 else {
107 ABORT("unsupported vector type");
108 }
109 result += to_string(type.columns());
110 return result;
111 }
112 case Type::kMatrix_Kind: {
113 String result;
114 Type component = type.componentType();
115 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
116 result = "mat";
117 }
118 else if (component == *fContext.fDouble_Type) {
119 result = "dmat";
120 }
121 else {
122 ABORT("unsupported matrix type");
123 }
124 result += to_string(type.columns());
125 if (type.columns() != type.rows()) {
126 result += "x";
127 result += to_string(type.rows());
128 }
129 return result;
130 }
131 case Type::kArray_Kind: {
132 String result = this->getTypeName(type.componentType()) + "[";
133 if (type.columns() != -1) {
134 result += to_string(type.columns());
135 }
136 result += "]";
137 return result;
138 }
139 case Type::kScalar_Kind: {
140 if (type == *fContext.fHalf_Type) {
141 return "float";
142 }
143 else if (type == *fContext.fShort_Type) {
144 return "int";
145 }
146 else if (type == *fContext.fUShort_Type) {
147 return "uint";
148 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400149 else if (type == *fContext.fByte_Type) {
150 return "int";
151 }
152 else if (type == *fContext.fUByte_Type) {
153 return "uint";
154 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400155 else {
156 return type.name();
157 }
158 break;
159 }
160 default:
161 return type.name();
162 }
163}
164
ethannicholasf789b382016-08-03 12:43:36 -0700165void GLSLCodeGenerator::writeType(const Type& type) {
166 if (type.kind() == Type::kStruct_Kind) {
167 for (const Type* search : fWrittenStructs) {
168 if (*search == type) {
169 // already written
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700170 this->write(type.fName);
ethannicholasf789b382016-08-03 12:43:36 -0700171 return;
172 }
173 }
174 fWrittenStructs.push_back(&type);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700175 this->write("struct ");
176 this->write(type.fName);
177 this->writeLine(" {");
ethannicholasf789b382016-08-03 12:43:36 -0700178 fIndentation++;
179 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700180 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400181 this->writeTypePrecision(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700182 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -0700183 this->writeType(*f.fType);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700184 this->write(" ");
185 this->write(f.fName);
186 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -0700187 }
188 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -0500189 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -0700190 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400191 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700192 }
193}
194
195void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
196 switch (expr.fKind) {
197 case Expression::kBinary_Kind:
198 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
199 break;
200 case Expression::kBoolLiteral_Kind:
201 this->writeBoolLiteral((BoolLiteral&) expr);
202 break;
203 case Expression::kConstructor_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400204 this->writeConstructor((Constructor&) expr, parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700205 break;
206 case Expression::kIntLiteral_Kind:
207 this->writeIntLiteral((IntLiteral&) expr);
208 break;
209 case Expression::kFieldAccess_Kind:
210 this->writeFieldAccess(((FieldAccess&) expr));
211 break;
212 case Expression::kFloatLiteral_Kind:
213 this->writeFloatLiteral(((FloatLiteral&) expr));
214 break;
215 case Expression::kFunctionCall_Kind:
216 this->writeFunctionCall((FunctionCall&) expr);
217 break;
218 case Expression::kPrefix_Kind:
219 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
220 break;
221 case Expression::kPostfix_Kind:
222 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
223 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400224 case Expression::kSetting_Kind:
225 this->writeSetting((Setting&) expr);
226 break;
ethannicholasf789b382016-08-03 12:43:36 -0700227 case Expression::kSwizzle_Kind:
228 this->writeSwizzle((Swizzle&) expr);
229 break;
230 case Expression::kVariableReference_Kind:
231 this->writeVariableReference((VariableReference&) expr);
232 break;
233 case Expression::kTernary_Kind:
234 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
235 break;
236 case Expression::kIndex_Kind:
237 this->writeIndexExpression((IndexExpression&) expr);
238 break;
239 default:
240 ABORT("unsupported expression: %s", expr.description().c_str());
241 }
242}
243
ethannicholas5961bc92016-10-12 06:39:56 -0700244static bool is_abs(Expression& expr) {
245 if (expr.fKind != Expression::kFunctionCall_Kind) {
246 return false;
247 }
248 return ((FunctionCall&) expr).fFunction.fName == "abs";
249}
250
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500251// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700252// Tegra3 compiler bug.
253void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400254 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
256 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400257 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.fType) +
258 this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
259 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.fType) +
260 this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700261 this->write("((" + tmpVar1 + " = ");
262 this->writeExpression(absExpr, kTopLevel_Precedence);
263 this->write(") < (" + tmpVar2 + " = ");
264 this->writeExpression(otherExpr, kAssignment_Precedence);
265 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
266}
267
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500268void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
269 this->write("(1.0 / sqrt(");
270 this->writeExpression(x, kTopLevel_Precedence);
271 this->write("))");
272}
273
274void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
275 String name;
276 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
277 name = "_determinant2";
278 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
279 fWrittenIntrinsics.insert(name);
280 fExtraFunctions.writeText((
281 "float " + name + "(mat2 m) {"
282 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
283 "}"
284 ).c_str());
285 }
286 }
287 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
288 name = "_determinant3";
289 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
290 fWrittenIntrinsics.insert(name);
291 fExtraFunctions.writeText((
292 "float " + name + "(mat3 m) {"
293 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
294 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
295 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
296 " float b01 = a22 * a11 - a12 * a21;"
297 " float b11 = -a22 * a10 + a12 * a20;"
298 " float b21 = a21 * a10 - a11 * a20;"
299 " return a00 * b01 + a01 * b11 + a02 * b21;"
300 "}"
301 ).c_str());
302 }
303 }
304 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
305 name = "_determinant3";
306 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
307 fWrittenIntrinsics.insert(name);
308 fExtraFunctions.writeText((
309 "mat4 " + name + "(mat4 m) {"
310 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
311 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
312 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
313 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
314 " float b00 = a00 * a11 - a01 * a10;"
315 " float b01 = a00 * a12 - a02 * a10;"
316 " float b02 = a00 * a13 - a03 * a10;"
317 " float b03 = a01 * a12 - a02 * a11;"
318 " float b04 = a01 * a13 - a03 * a11;"
319 " float b05 = a02 * a13 - a03 * a12;"
320 " float b06 = a20 * a31 - a21 * a30;"
321 " float b07 = a20 * a32 - a22 * a30;"
322 " float b08 = a20 * a33 - a23 * a30;"
323 " float b09 = a21 * a32 - a22 * a31;"
324 " float b10 = a21 * a33 - a23 * a31;"
325 " float b11 = a22 * a33 - a23 * a32;"
326 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
327 "}"
328 ).c_str());
329 }
330 }
331 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400332 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500333 }
334 this->write(name + "(");
335 this->writeExpression(mat, kTopLevel_Precedence);
336 this->write(")");
337}
338
339void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
340 String name;
341 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
342 name = "_inverse2";
343 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
344 fWrittenIntrinsics.insert(name);
345 fExtraFunctions.writeText((
346 "mat2 " + name + "(mat2 m) {"
347 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
348 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
349 "}"
350 ).c_str());
351 }
352 }
353 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
354 name = "_inverse3";
355 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
356 fWrittenIntrinsics.insert(name);
357 fExtraFunctions.writeText((
358 "mat3 " + name + "(mat3 m) {"
359 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
360 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
361 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
362 " float b01 = a22 * a11 - a12 * a21;"
363 " float b11 = -a22 * a10 + a12 * a20;"
364 " float b21 = a21 * a10 - a11 * a20;"
365 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
366 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
367 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
368 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
369 "}"
370 ).c_str());
371 }
372 }
373 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
374 name = "_inverse4";
375 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
376 fWrittenIntrinsics.insert(name);
377 fExtraFunctions.writeText((
378 "mat4 " + name + "(mat4 m) {"
379 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
380 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
381 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
382 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
383 " float b00 = a00 * a11 - a01 * a10;"
384 " float b01 = a00 * a12 - a02 * a10;"
385 " float b02 = a00 * a13 - a03 * a10;"
386 " float b03 = a01 * a12 - a02 * a11;"
387 " float b04 = a01 * a13 - a03 * a11;"
388 " float b05 = a02 * a13 - a03 * a12;"
389 " float b06 = a20 * a31 - a21 * a30;"
390 " float b07 = a20 * a32 - a22 * a30;"
391 " float b08 = a20 * a33 - a23 * a30;"
392 " float b09 = a21 * a32 - a22 * a31;"
393 " float b10 = a21 * a33 - a23 * a31;"
394 " float b11 = a22 * a33 - a23 * a32;"
395 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
396 " b04 * b07 + b05 * b06;"
397 " return mat4("
398 " a11 * b11 - a12 * b10 + a13 * b09,"
399 " a02 * b10 - a01 * b11 - a03 * b09,"
400 " a31 * b05 - a32 * b04 + a33 * b03,"
401 " a22 * b04 - a21 * b05 - a23 * b03,"
402 " a12 * b08 - a10 * b11 - a13 * b07,"
403 " a00 * b11 - a02 * b08 + a03 * b07,"
404 " a32 * b02 - a30 * b05 - a33 * b01,"
405 " a20 * b05 - a22 * b02 + a23 * b01,"
406 " a10 * b10 - a11 * b08 + a13 * b06,"
407 " a01 * b08 - a00 * b10 - a03 * b06,"
408 " a30 * b04 - a31 * b02 + a33 * b00,"
409 " a21 * b02 - a20 * b04 - a23 * b00,"
410 " a11 * b07 - a10 * b09 - a12 * b06,"
411 " a00 * b09 - a01 * b07 + a02 * b06,"
412 " a31 * b01 - a30 * b03 - a32 * b00,"
413 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
414 "}"
415 ).c_str());
416 }
417 }
418 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400419 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500420 }
421 this->write(name + "(");
422 this->writeExpression(mat, kTopLevel_Precedence);
423 this->write(")");
424}
425
426void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
427 String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
428 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
429 fWrittenIntrinsics.insert(name);
430 String type = this->getTypeName(mat.fType);
431 const Type& base = mat.fType.componentType();
432 String transposed = this->getTypeName(base.toCompound(fContext,
433 mat.fType.rows(),
434 mat.fType.columns()));
435 fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
436 transposed + "(").c_str());
437 const char* separator = "";
438 for (int row = 0; row < mat.fType.rows(); ++row) {
439 for (int column = 0; column < mat.fType.columns(); ++column) {
440 fExtraFunctions.writeText(separator);
441 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
442 "]").c_str());
443 separator = ", ";
444 }
445 }
446 fExtraFunctions.writeText("); }");
447 }
448 this->write(name + "(");
449 this->writeExpression(mat, kTopLevel_Precedence);
450 this->write(")");
451}
452
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400453std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
454 GLSLCodeGenerator::fFunctionClasses = nullptr;
455
ethannicholasf789b382016-08-03 12:43:36 -0700456void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400457#ifdef SKSL_STANDALONE
458 if (!fFunctionClasses) {
459#else
460 static SkOnce once;
461 once([] {
462#endif
463 fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
Adrienne Walker92b161f2018-08-22 10:41:52 -0700464 (*fFunctionClasses)["abs"] = FunctionClass::kAbs;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400465 (*fFunctionClasses)["atan"] = FunctionClass::kAtan;
466 (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
467 (*fFunctionClasses)["dFdx"] = FunctionClass::kDerivative;
468 (*fFunctionClasses)["dFdy"] = FunctionClass::kDerivative;
Chris Dalton09212192018-11-13 15:07:24 -0500469 (*fFunctionClasses)["fwidth"] = FunctionClass::kDerivative;
Chris Daltona7086182018-11-16 09:33:43 -0500470 (*fFunctionClasses)["fma"] = FunctionClass::kFMA;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400471 (*fFunctionClasses)["fract"] = FunctionClass::kFract;
472 (*fFunctionClasses)["inverse"] = FunctionClass::kInverse;
473 (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
474 (*fFunctionClasses)["min"] = FunctionClass::kMin;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700475 (*fFunctionClasses)["pow"] = FunctionClass::kPow;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400476 (*fFunctionClasses)["saturate"] = FunctionClass::kSaturate;
477 (*fFunctionClasses)["texture"] = FunctionClass::kTexture;
478 (*fFunctionClasses)["transpose"] = FunctionClass::kTranspose;
ethannicholas5961bc92016-10-12 06:39:56 -0700479 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400480#ifndef SKSL_STANDALONE
481 );
482#endif
483 const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
484 fFunctionClasses->end();
Brian Osman8a83ca42018-02-12 14:32:17 -0500485 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400486 bool nameWritten = false;
487 if (found != fFunctionClasses->end()) {
488 switch (found->second) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700489 case FunctionClass::kAbs: {
490 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
491 break;
492 SkASSERT(c.fArguments.size() == 1);
493 if (c.fArguments[0]->fType != *fContext.fInt_Type)
494 break;
495 // abs(int) on Intel OSX is incorrect, so emulate it:
496 String name = "_absemulation";
497 this->write(name);
498 nameWritten = true;
499 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
500 fWrittenIntrinsics.insert(name);
501 fExtraFunctions.writeText((
502 "int " + name + "(int x) {\n"
503 " return x * sign(x);\n"
504 "}\n"
505 ).c_str());
506 }
507 break;
508 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400509 case FunctionClass::kAtan:
510 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
511 c.fArguments.size() == 2 &&
512 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
513 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
514 if (p.fOperator == Token::MINUS) {
515 this->write("atan(");
516 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
517 this->write(", -1.0 * ");
518 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
519 this->write(")");
520 return;
521 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500522 }
523 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400524 case FunctionClass::kDerivative:
525 if (!fFoundDerivatives &&
526 fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
527 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
528 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
529 fFoundDerivatives = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500530 }
531 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400532 case FunctionClass::kDeterminant:
533 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
534 SkASSERT(c.fArguments.size() == 1);
535 this->writeDeterminantHack(*c.fArguments[0]);
536 return;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500537 }
538 break;
Chris Daltona7086182018-11-16 09:33:43 -0500539 case FunctionClass::kFMA:
540 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
541 SkASSERT(c.fArguments.size() == 3);
542 this->write("((");
543 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
544 this->write(") * (");
545 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
546 this->write(") + (");
547 this->writeExpression(*c.fArguments[2], kSequence_Precedence);
548 this->write("))");
549 return;
550 }
551 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400552 case FunctionClass::kFract:
553 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
554 SkASSERT(c.fArguments.size() == 1);
555 this->write("(0.5 - sign(");
556 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
557 this->write(") * (0.5 - fract(abs(");
558 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
559 this->write("))))");
560 return;
561 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500562 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400563 case FunctionClass::kInverse:
564 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
565 SkASSERT(c.fArguments.size() == 1);
566 this->writeInverseHack(*c.fArguments[0]);
567 return;
568 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500569 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400570 case FunctionClass::kInverseSqrt:
571 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
572 SkASSERT(c.fArguments.size() == 1);
573 this->writeInverseSqrtHack(*c.fArguments[0]);
574 return;
575 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500576 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400577 case FunctionClass::kMin:
578 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
579 SkASSERT(c.fArguments.size() == 2);
580 if (is_abs(*c.fArguments[0])) {
581 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
582 return;
583 }
584 if (is_abs(*c.fArguments[1])) {
585 // note that this violates the GLSL left-to-right evaluation semantics.
586 // I doubt it will ever end up mattering, but it's worth calling out.
587 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
588 return;
589 }
590 }
591 break;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700592 case FunctionClass::kPow:
593 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
594 break;
595 }
596 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
597 // constant. It's hard to tell what constitutes "constant" here
598 // so just replace in all cases.
599
600 // Change pow(x, y) into exp2(y * log2(x))
601 this->write("exp2(");
602 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
603 this->write(" * log2(");
604 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
605 this->write("))");
606 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400607 case FunctionClass::kSaturate:
608 SkASSERT(c.fArguments.size() == 1);
609 this->write("clamp(");
610 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
611 this->write(", 0.0, 1.0)");
612 return;
613 case FunctionClass::kTexture: {
614 const char* dim = "";
615 bool proj = false;
616 switch (c.fArguments[0]->fType.dimensions()) {
617 case SpvDim1D:
618 dim = "1D";
619 isTextureFunctionWithBias = true;
620 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
621 proj = false;
622 } else {
623 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
624 proj = true;
625 }
626 break;
627 case SpvDim2D:
628 dim = "2D";
629 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
630 isTextureFunctionWithBias = true;
631 }
632 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
633 proj = false;
634 } else {
635 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
636 proj = true;
637 }
638 break;
639 case SpvDim3D:
640 dim = "3D";
641 isTextureFunctionWithBias = true;
642 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
643 proj = false;
644 } else {
645 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
646 proj = true;
647 }
648 break;
649 case SpvDimCube:
650 dim = "Cube";
651 isTextureFunctionWithBias = true;
652 proj = false;
653 break;
654 case SpvDimRect:
655 dim = "Rect";
656 proj = false;
657 break;
658 case SpvDimBuffer:
659 SkASSERT(false); // doesn't exist
660 dim = "Buffer";
661 proj = false;
662 break;
663 case SpvDimSubpassData:
664 SkASSERT(false); // doesn't exist
665 dim = "SubpassData";
666 proj = false;
667 break;
668 }
669 this->write("texture");
670 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
671 this->write(dim);
672 }
673 if (proj) {
674 this->write("Proj");
675 }
676 nameWritten = true;
677 break;
678 }
679 case FunctionClass::kTranspose:
680 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
681 SkASSERT(c.fArguments.size() == 1);
682 this->writeTransposeHack(*c.fArguments[0]);
683 return;
684 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500685 break;
686 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400687 }
688 if (!nameWritten) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500689 this->write(c.fFunction.fName);
690 }
691 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700692 const char* separator = "";
693 for (const auto& arg : c.fArguments) {
694 this->write(separator);
695 separator = ", ";
696 this->writeExpression(*arg, kSequence_Precedence);
697 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500698 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
699 this->write(", -0.5");
700 }
ethannicholasf789b382016-08-03 12:43:36 -0700701 this->write(")");
702}
703
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400704void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
705 if (c.fArguments.size() == 1 &&
706 this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
707 // in cases like half(float), they're different types as far as SkSL is concerned but the
708 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
709 // out the inner expression here.
710 this->writeExpression(*c.fArguments[0], parentPrecedence);
711 return;
712 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400713 this->writeType(c.fType);
714 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700715 const char* separator = "";
716 for (const auto& arg : c.fArguments) {
717 this->write(separator);
718 separator = ", ";
719 this->writeExpression(*arg, kSequence_Precedence);
720 }
721 this->write(")");
722}
723
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500724void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000725 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500726 if (!fSetupFragCoordWorkaround) {
727 const char* precision = usesPrecisionModifiers() ? "highp " : "";
728 fFunctionHeader += precision;
729 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
730 fFunctionHeader += precision;
731 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
732 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
733 // Ensure that we get exact .5 values for x and y.
734 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
735 "vec2(.5);\n";
736 fSetupFragCoordWorkaround = true;
737 }
738 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000739 return;
740 }
741
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500742 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
743 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
744 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
745 if (!fProgram.fSettings.fFlipY) {
746 this->write("gl_FragCoord");
747 } else if (const char* extension =
Ethan Nicholascd700e92018-08-24 16:43:57 -0400748 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500749 if (!fSetupFragPositionGlobal) {
750 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400751 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500752 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400753 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500754 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000755 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500756 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000757 } else {
Ethan Nicholascd700e92018-08-24 16:43:57 -0400758 if (!fSetupFragPositionLocal) {
Michael Ludwiga34e6ea2018-12-06 12:53:54 -0500759 // Accessing the components of gl_FragCoord cause pretty noticeable performance hits on
760 // the Mali400. Reading from the z component of gl_FragCoord or _sktmpCoord, flipping
761 // the y value after assigning to sk_FragCoord, or not using a temp variable are not as
762 // optimal.
Michael Ludwig5e1f6ea2018-12-03 15:14:50 -0500763 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
Michael Ludwiga34e6ea2018-12-06 12:53:54 -0500764 fFunctionHeader += " vec4 _sktmpCoord = gl_FragCoord;\n";
765 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
766 fFunctionHeader += " vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
767 " - _sktmpCoord.y, 0.0, _sktmpCoord.w);\n";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500768 fSetupFragPositionLocal = true;
769 }
770 this->write("sk_FragCoord");
771 }
772}
773
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500774void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
775 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
776 case SK_FRAGCOLOR_BUILTIN:
777 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
778 this->write("sk_FragColor");
779 } else {
780 this->write("gl_FragColor");
781 }
782 break;
783 case SK_FRAGCOORD_BUILTIN:
784 this->writeFragCoord();
785 break;
Ethan Nicholascd700e92018-08-24 16:43:57 -0400786 case SK_WIDTH_BUILTIN:
787 this->write("u_skRTWidth");
788 break;
789 case SK_HEIGHT_BUILTIN:
790 this->write("u_skRTHeight");
791 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600792 case SK_CLOCKWISE_BUILTIN:
Chris Daltonc8ece3d2018-07-30 15:03:45 -0600793 this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
Chris Dalton49d14e92018-07-27 12:38:35 -0600794 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500795 case SK_VERTEXID_BUILTIN:
796 this->write("gl_VertexID");
797 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600798 case SK_INSTANCEID_BUILTIN:
799 this->write("gl_InstanceID");
800 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500801 case SK_CLIPDISTANCE_BUILTIN:
802 this->write("gl_ClipDistance");
803 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500804 case SK_IN_BUILTIN:
805 this->write("gl_in");
806 break;
807 case SK_INVOCATIONID_BUILTIN:
808 this->write("gl_InvocationID");
809 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400810 case SK_LASTFRAGCOLOR_BUILTIN:
811 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
812 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500813 default:
814 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700815 }
ethannicholasf789b382016-08-03 12:43:36 -0700816}
817
818void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
819 this->writeExpression(*expr.fBase, kPostfix_Precedence);
820 this->write("[");
821 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
822 this->write("]");
823}
824
Brian Osmancd3261a2018-01-16 13:52:29 +0000825bool is_sk_position(const FieldAccess& f) {
826 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
827}
828
ethannicholasf789b382016-08-03 12:43:36 -0700829void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
830 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
831 this->writeExpression(*f.fBase, kPostfix_Precedence);
832 this->write(".");
833 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500834 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
835 case SK_CLIPDISTANCE_BUILTIN:
836 this->write("gl_ClipDistance");
837 break;
838 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400839 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
840 if (name == "sk_Position") {
841 this->write("gl_Position");
842 } else if (name == "sk_PointSize") {
843 this->write("gl_PointSize");
844 } else {
845 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
846 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500847 }
ethannicholasf789b382016-08-03 12:43:36 -0700848}
849
850void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
851 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
852 this->write(".");
853 for (int c : swizzle.fComponents) {
854 this->write(&("x\0y\0z\0w\0"[c * 2]));
855 }
856}
857
Ethan Nicholas762466e2017-06-29 10:03:38 -0400858GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -0700859 switch (op) {
860 case Token::STAR: // fall through
861 case Token::SLASH: // fall through
862 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
863 case Token::PLUS: // fall through
864 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
865 case Token::SHL: // fall through
866 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
867 case Token::LT: // fall through
868 case Token::GT: // fall through
869 case Token::LTEQ: // fall through
870 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
871 case Token::EQEQ: // fall through
872 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
873 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
874 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
875 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
876 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
877 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
878 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
879 case Token::EQ: // fall through
880 case Token::PLUSEQ: // fall through
881 case Token::MINUSEQ: // fall through
882 case Token::STAREQ: // fall through
883 case Token::SLASHEQ: // fall through
884 case Token::PERCENTEQ: // fall through
885 case Token::SHLEQ: // fall through
886 case Token::SHREQ: // fall through
887 case Token::LOGICALANDEQ: // fall through
888 case Token::LOGICALXOREQ: // fall through
889 case Token::LOGICALOREQ: // fall through
890 case Token::BITWISEANDEQ: // fall through
891 case Token::BITWISEXOREQ: // fall through
892 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400893 case Token::COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -0700894 default: ABORT("unsupported binary operator");
895 }
896}
897
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400898void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -0700899 Precedence parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700900 if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
901 (b.fOperator == Token::LOGICALAND || b.fOperator == Token::LOGICALOR)) {
902 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
903 return;
904 }
905
Ethan Nicholas762466e2017-06-29 10:03:38 -0400906 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -0700907 if (precedence >= parentPrecedence) {
908 this->write("(");
909 }
Ethan Nicholas0b631962018-07-24 13:41:11 -0400910 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
911 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +0000912 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
913 is_sk_position((FieldAccess&) *b.fLeft) &&
914 !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
915 !fProgram.fSettings.fCaps->canUseFragCoord();
916 if (positionWorkaround) {
917 this->write("sk_FragCoord_Workaround = (");
918 }
ethannicholasf789b382016-08-03 12:43:36 -0700919 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700920 this->write(" ");
921 this->write(Compiler::OperatorName(b.fOperator));
922 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -0700923 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +0000924 if (positionWorkaround) {
925 this->write(")");
926 }
ethannicholasf789b382016-08-03 12:43:36 -0700927 if (precedence >= parentPrecedence) {
928 this->write(")");
929 }
930}
931
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700932void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
933 Precedence parentPrecedence) {
934 if (kTernary_Precedence >= parentPrecedence) {
935 this->write("(");
936 }
937
938 // Transform:
939 // a && b => a ? b : false
940 // a || b => a ? true : b
941 this->writeExpression(*b.fLeft, kTernary_Precedence);
942 this->write(" ? ");
943 if (b.fOperator == Token::LOGICALAND) {
944 this->writeExpression(*b.fRight, kTernary_Precedence);
945 } else {
946 BoolLiteral boolTrue(fContext, -1, true);
947 this->writeBoolLiteral(boolTrue);
948 }
949 this->write(" : ");
950 if (b.fOperator == Token::LOGICALAND) {
951 BoolLiteral boolFalse(fContext, -1, false);
952 this->writeBoolLiteral(boolFalse);
953 } else {
954 this->writeExpression(*b.fRight, kTernary_Precedence);
955 }
956 if (kTernary_Precedence >= parentPrecedence) {
957 this->write(")");
958 }
959}
960
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400961void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -0700962 Precedence parentPrecedence) {
963 if (kTernary_Precedence >= parentPrecedence) {
964 this->write("(");
965 }
966 this->writeExpression(*t.fTest, kTernary_Precedence);
967 this->write(" ? ");
968 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
969 this->write(" : ");
970 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
971 if (kTernary_Precedence >= parentPrecedence) {
972 this->write(")");
973 }
974}
975
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400976void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700977 Precedence parentPrecedence) {
978 if (kPrefix_Precedence >= parentPrecedence) {
979 this->write("(");
980 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700981 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700982 this->writeExpression(*p.fOperand, kPrefix_Precedence);
983 if (kPrefix_Precedence >= parentPrecedence) {
984 this->write(")");
985 }
986}
987
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400988void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700989 Precedence parentPrecedence) {
990 if (kPostfix_Precedence >= parentPrecedence) {
991 this->write("(");
992 }
993 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700994 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700995 if (kPostfix_Precedence >= parentPrecedence) {
996 this->write(")");
997 }
998}
999
1000void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1001 this->write(b.fValue ? "true" : "false");
1002}
1003
1004void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -07001005 if (i.fType == *fContext.fUInt_Type) {
1006 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -05001007 } else if (i.fType == *fContext.fUShort_Type) {
1008 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001009 } else if (i.fType == *fContext.fUByte_Type) {
1010 this->write(to_string(i.fValue & 0xff) + "u");
1011 } else {
ethannicholas5961bc92016-10-12 06:39:56 -07001012 this->write(to_string((int32_t) i.fValue));
1013 }
ethannicholasf789b382016-08-03 12:43:36 -07001014}
1015
1016void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1017 this->write(to_string(f.fValue));
1018}
1019
Ethan Nicholas762466e2017-06-29 10:03:38 -04001020void GLSLCodeGenerator::writeSetting(const Setting& s) {
1021 ABORT("internal error; setting was not folded to a constant during compilation\n");
1022}
1023
ethannicholasf789b382016-08-03 12:43:36 -07001024void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholas00543112018-07-31 09:44:36 -04001025 if (fProgramKind != Program::kPipelineStage_Kind) {
1026 this->writeTypePrecision(f.fDeclaration.fReturnType);
1027 this->writeType(f.fDeclaration.fReturnType);
1028 this->write(" " + f.fDeclaration.fName + "(");
1029 const char* separator = "";
1030 for (const auto& param : f.fDeclaration.fParameters) {
1031 this->write(separator);
1032 separator = ", ";
1033 this->writeModifiers(param->fModifiers, false);
1034 std::vector<int> sizes;
1035 const Type* type = &param->fType;
1036 while (type->kind() == Type::kArray_Kind) {
1037 sizes.push_back(type->columns());
1038 type = &type->componentType();
1039 }
1040 this->writeTypePrecision(*type);
1041 this->writeType(*type);
1042 this->write(" " + param->fName);
1043 for (int s : sizes) {
1044 if (s <= 0) {
1045 this->write("[]");
1046 } else {
1047 this->write("[" + to_string(s) + "]");
1048 }
ethannicholas5961bc92016-10-12 06:39:56 -07001049 }
1050 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001051 this->writeLine(") {");
1052 fIndentation++;
ethannicholasf789b382016-08-03 12:43:36 -07001053 }
ethannicholas5961bc92016-10-12 06:39:56 -07001054 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001055 OutputStream* oldOut = fOut;
1056 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001057 fOut = &buffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04001058 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas00543112018-07-31 09:44:36 -04001059 if (fProgramKind != Program::kPipelineStage_Kind) {
1060 fIndentation--;
1061 this->writeLine("}");
1062 }
ethannicholas5961bc92016-10-12 06:39:56 -07001063
1064 fOut = oldOut;
1065 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001066 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001067}
1068
Greg Daniel64773e62016-11-22 09:44:03 -05001069void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001070 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001071 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1072 this->write("flat ");
1073 }
ethannicholas5961bc92016-10-12 06:39:56 -07001074 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1075 this->write("noperspective ");
1076 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001077 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001078 if (layout.size()) {
1079 this->write(layout + " ");
1080 }
Brian Salomonf9f45122016-11-29 11:59:17 -05001081 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1082 this->write("readonly ");
1083 }
1084 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1085 this->write("writeonly ");
1086 }
1087 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1088 this->write("coherent ");
1089 }
1090 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1091 this->write("volatile ");
1092 }
1093 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1094 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -07001095 }
Greg Daniel64773e62016-11-22 09:44:03 -05001096 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001097 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1098 this->write("inout ");
1099 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001100 if (globalContext &&
1101 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001102 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1103 : "varying ");
1104 } else {
1105 this->write("in ");
1106 }
1107 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001108 if (globalContext &&
1109 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001110 this->write("varying ");
1111 } else {
1112 this->write("out ");
1113 }
1114 }
1115 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1116 this->write("uniform ");
1117 }
1118 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1119 this->write("const ");
1120 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001121 if (usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001122 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
1123 this->write("lowp ");
1124 }
1125 if (modifiers.fFlags & Modifiers::kMediump_Flag) {
1126 this->write("mediump ");
1127 }
1128 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
1129 this->write("highp ");
1130 }
1131 }
ethannicholasf789b382016-08-03 12:43:36 -07001132}
1133
1134void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001135 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001136 return;
1137 }
ethannicholas5961bc92016-10-12 06:39:56 -07001138 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001139 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001140 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001141 const Type* structType = &intf.fVariable.fType;
1142 while (structType->kind() == Type::kArray_Kind) {
1143 structType = &structType->componentType();
1144 }
1145 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001146 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001147 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001148 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001149 this->writeLine(" " + f.fName + ";");
1150 }
1151 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001152 this->write("}");
1153 if (intf.fInstanceName.size()) {
1154 this->write(" ");
1155 this->write(intf.fInstanceName);
1156 for (const auto& size : intf.fSizes) {
1157 this->write("[");
1158 if (size) {
1159 this->writeExpression(*size, kTopLevel_Precedence);
1160 }
1161 this->write("]");
1162 }
1163 }
1164 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001165}
1166
Ethan Nicholas762466e2017-06-29 10:03:38 -04001167void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1168 this->writeExpression(value, kTopLevel_Precedence);
1169}
1170
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001171const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1172 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001173 switch (type.kind()) {
1174 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001175 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1176 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001177 if (fProgram.fSettings.fForceHighPrecision ||
1178 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1179 return "highp ";
1180 }
1181 return "mediump ";
1182 }
1183 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001184 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001185 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001186 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1187 type == *fContext.fUInt_Type) {
1188 return "highp ";
1189 }
1190 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001191 case Type::kVector_Kind: // fall through
1192 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001193 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001194 default:
1195 break;
1196 }
1197 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001198 return "";
1199}
1200
1201void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1202 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001203}
1204
ethannicholas5961bc92016-10-12 06:39:56 -07001205void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001206 if (!decl.fVars.size()) {
1207 return;
1208 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001209 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001210 for (const auto& stmt : decl.fVars) {
1211 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001212 if (wroteType) {
1213 this->write(", ");
1214 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001215 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001216 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001217 this->writeType(decl.fBaseType);
1218 this->write(" ");
1219 wroteType = true;
1220 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001221 this->write(var.fVar->fName);
1222 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001223 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001224 if (size) {
1225 this->writeExpression(*size, kTopLevel_Precedence);
1226 }
ethannicholasf789b382016-08-03 12:43:36 -07001227 this->write("]");
1228 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001229 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001230 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001231 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001232 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001233 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001234 if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001235 this->writeExtension(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
Brian Salomon2a51de82016-11-16 12:06:01 -05001236 }
1237 fFoundImageDecl = true;
1238 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001239 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1240 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001241 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001242 }
Brian Osman061020e2018-04-17 14:22:15 -04001243 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001244 this->writeExtension(
1245 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001246 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001247 fFoundExternalSamplerDecl = true;
1248 }
ethannicholasf789b382016-08-03 12:43:36 -07001249 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001250 if (wroteType) {
1251 this->write(";");
1252 }
ethannicholasf789b382016-08-03 12:43:36 -07001253}
1254
1255void GLSLCodeGenerator::writeStatement(const Statement& s) {
1256 switch (s.fKind) {
1257 case Statement::kBlock_Kind:
1258 this->writeBlock((Block&) s);
1259 break;
1260 case Statement::kExpression_Kind:
1261 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1262 this->write(";");
1263 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001264 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001265 this->writeReturnStatement((ReturnStatement&) s);
1266 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001267 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001268 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001269 break;
1270 case Statement::kIf_Kind:
1271 this->writeIfStatement((IfStatement&) s);
1272 break;
1273 case Statement::kFor_Kind:
1274 this->writeForStatement((ForStatement&) s);
1275 break;
1276 case Statement::kWhile_Kind:
1277 this->writeWhileStatement((WhileStatement&) s);
1278 break;
1279 case Statement::kDo_Kind:
1280 this->writeDoStatement((DoStatement&) s);
1281 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001282 case Statement::kSwitch_Kind:
1283 this->writeSwitchStatement((SwitchStatement&) s);
1284 break;
ethannicholasf789b382016-08-03 12:43:36 -07001285 case Statement::kBreak_Kind:
1286 this->write("break;");
1287 break;
1288 case Statement::kContinue_Kind:
1289 this->write("continue;");
1290 break;
1291 case Statement::kDiscard_Kind:
1292 this->write("discard;");
1293 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001294 case Statement::kNop_Kind:
1295 this->write(";");
1296 break;
ethannicholasf789b382016-08-03 12:43:36 -07001297 default:
1298 ABORT("unsupported statement: %s", s.description().c_str());
1299 }
1300}
1301
Ethan Nicholascb670962017-04-20 19:31:52 -04001302void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1303 for (const auto& s : statements) {
1304 if (!s->isEmpty()) {
1305 this->writeStatement(*s);
1306 this->writeLine();
1307 }
1308 }
1309}
1310
ethannicholasf789b382016-08-03 12:43:36 -07001311void GLSLCodeGenerator::writeBlock(const Block& b) {
1312 this->writeLine("{");
1313 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001314 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001315 fIndentation--;
1316 this->write("}");
1317}
1318
1319void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1320 this->write("if (");
1321 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1322 this->write(") ");
1323 this->writeStatement(*stmt.fIfTrue);
1324 if (stmt.fIfFalse) {
1325 this->write(" else ");
1326 this->writeStatement(*stmt.fIfFalse);
1327 }
1328}
1329
1330void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1331 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001332 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001333 this->writeStatement(*f.fInitializer);
1334 } else {
1335 this->write("; ");
1336 }
1337 if (f.fTest) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001338 if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1339 std::unique_ptr<Expression> and_true(new BinaryExpression(
1340 -1, f.fTest->clone(), Token::LOGICALAND,
1341 std::unique_ptr<BoolLiteral>(new BoolLiteral(fContext, -1,
1342 true)),
1343 *fContext.fBool_Type));
1344 this->writeExpression(*and_true, kTopLevel_Precedence);
1345 } else {
1346 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1347 }
ethannicholasf789b382016-08-03 12:43:36 -07001348 }
1349 this->write("; ");
1350 if (f.fNext) {
1351 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1352 }
1353 this->write(") ");
1354 this->writeStatement(*f.fStatement);
1355}
1356
1357void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1358 this->write("while (");
1359 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1360 this->write(") ");
1361 this->writeStatement(*w.fStatement);
1362}
1363
1364void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001365 if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1366 this->write("do ");
1367 this->writeStatement(*d.fStatement);
1368 this->write(" while (");
1369 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1370 this->write(");");
1371 return;
1372 }
1373
1374 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1375 // do {
1376 // CODE;
1377 // } while (CONDITION)
1378 //
1379 // to loops of the form
1380 // bool temp = false;
1381 // while (true) {
1382 // if (temp) {
1383 // if (!CONDITION) {
1384 // break;
1385 // }
1386 // }
1387 // temp = true;
1388 // CODE;
1389 // }
1390 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1391 this->write("bool ");
1392 this->write(tmpVar);
1393 this->writeLine(" = false;");
1394 this->writeLine("while (true) {");
1395 fIndentation++;
1396 this->write("if (");
1397 this->write(tmpVar);
1398 this->writeLine(") {");
1399 fIndentation++;
1400 this->write("if (!");
1401 this->writeExpression(*d.fTest, kPrefix_Precedence);
1402 this->writeLine(") {");
1403 fIndentation++;
1404 this->writeLine("break;");
1405 fIndentation--;
1406 this->writeLine("}");
1407 fIndentation--;
1408 this->writeLine("}");
1409 this->write(tmpVar);
1410 this->writeLine(" = true;");
ethannicholasf789b382016-08-03 12:43:36 -07001411 this->writeStatement(*d.fStatement);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001412 this->writeLine();
1413 fIndentation--;
1414 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001415}
1416
Ethan Nicholasaf197692017-02-27 13:26:45 -05001417void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1418 this->write("switch (");
1419 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1420 this->writeLine(") {");
1421 fIndentation++;
1422 for (const auto& c : s.fCases) {
1423 if (c->fValue) {
1424 this->write("case ");
1425 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1426 this->writeLine(":");
1427 } else {
1428 this->writeLine("default:");
1429 }
1430 fIndentation++;
1431 for (const auto& stmt : c->fStatements) {
1432 this->writeStatement(*stmt);
1433 this->writeLine();
1434 }
1435 fIndentation--;
1436 }
1437 fIndentation--;
1438 this->write("}");
1439}
1440
ethannicholasf789b382016-08-03 12:43:36 -07001441void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1442 this->write("return");
1443 if (r.fExpression) {
1444 this->write(" ");
1445 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1446 }
1447 this->write(";");
1448}
1449
Ethan Nicholas762466e2017-06-29 10:03:38 -04001450void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001451 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001452 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001453}
1454
Ethan Nicholas762466e2017-06-29 10:03:38 -04001455void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1456 switch (e.fKind) {
1457 case ProgramElement::kExtension_Kind:
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001458 this->writeExtension(((Extension&) e).fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001459 break;
1460 case ProgramElement::kVar_Kind: {
1461 VarDeclarations& decl = (VarDeclarations&) e;
1462 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001463 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001464 if (builtin == -1) {
1465 // normal var
1466 this->writeVarDeclarations(decl, true);
1467 this->writeLine();
1468 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1469 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
Brian Salomondc092132018-04-04 10:14:16 -04001470 if (fProgram.fSettings.fFragColorIsInOut) {
1471 this->write("inout ");
1472 } else {
1473 this->write("out ");
1474 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001475 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001476 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001477 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001478 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001479 }
Mike Klein5ce39722017-06-27 22:52:03 +00001480 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001481 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001482 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001483 case ProgramElement::kInterfaceBlock_Kind:
1484 this->writeInterfaceBlock((InterfaceBlock&) e);
1485 break;
1486 case ProgramElement::kFunction_Kind:
1487 this->writeFunction((FunctionDefinition&) e);
1488 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001489 case ProgramElement::kModifiers_Kind: {
1490 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1491 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1492 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001493 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001494 }
1495 fFoundGSInvocations = true;
1496 }
1497 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001498 this->writeLine(";");
1499 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001500 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001501 case ProgramElement::kEnum_Kind:
1502 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001503 default:
1504 printf("%s\n", e.description().c_str());
1505 ABORT("unsupported program element");
Ethan Nicholasc0709392017-06-27 11:20:22 -04001506 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001507}
1508
Ethan Nicholascd700e92018-08-24 16:43:57 -04001509void GLSLCodeGenerator::writeInputVars() {
1510 if (fProgram.fInputs.fRTWidth) {
1511 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1512 fGlobals.writeText("uniform ");
1513 fGlobals.writeText(precision);
1514 fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1515 }
1516 if (fProgram.fInputs.fRTHeight) {
1517 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1518 fGlobals.writeText("uniform ");
1519 fGlobals.writeText(precision);
1520 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1521 }
1522}
1523
Ethan Nicholas762466e2017-06-29 10:03:38 -04001524bool GLSLCodeGenerator::generateCode() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001525 if (fProgramKind != Program::kPipelineStage_Kind) {
1526 this->writeHeader();
1527 }
Chris Dalton8fd79552018-01-11 00:46:14 -05001528 if (Program::kGeometry_Kind == fProgramKind &&
1529 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001530 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001531 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001532 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001533 StringStream body;
1534 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001535 for (const auto& e : fProgram) {
1536 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001537 }
1538 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001539
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001540 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001541 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001542 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001543
1544 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1545 Layout layout;
1546 switch (fProgram.fKind) {
1547 case Program::kVertex_Kind: {
1548 Modifiers modifiers(layout, Modifiers::kOut_Flag | Modifiers::kHighp_Flag);
1549 this->writeModifiers(modifiers, true);
1550 this->write("vec4 sk_FragCoord_Workaround;\n");
1551 break;
1552 }
1553 case Program::kFragment_Kind: {
1554 Modifiers modifiers(layout, Modifiers::kIn_Flag | Modifiers::kHighp_Flag);
1555 this->writeModifiers(modifiers, true);
1556 this->write("vec4 sk_FragCoord_Workaround;\n");
1557 break;
1558 }
1559 default:
1560 break;
1561 }
1562 }
1563
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001564 if (this->usesPrecisionModifiers()) {
1565 this->writeLine("precision mediump float;");
1566 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001567 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001568 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001569 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001570}
1571
1572}