blob: f0c97a319d817ee3e09453ba21ab2e5b999ee98e [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
18namespace SkSL {
19
20void GLSLCodeGenerator::write(const char* s) {
21 if (s[0] == 0) {
22 return;
23 }
24 if (fAtLineStart) {
25 for (int i = 0; i < fIndentation; i++) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050026 fOut->writeText(" ");
ethannicholasf789b382016-08-03 12:43:36 -070027 }
28 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050029 fOut->writeText(s);
ethannicholasf789b382016-08-03 12:43:36 -070030 fAtLineStart = false;
31}
32
33void GLSLCodeGenerator::writeLine(const char* s) {
34 this->write(s);
Ethan Nicholas762466e2017-06-29 10:03:38 -040035 fOut->writeText(fLineEnding);
ethannicholasf789b382016-08-03 12:43:36 -070036 fAtLineStart = true;
37}
38
Ethan Nicholas0df1b042017-03-31 13:56:23 -040039void GLSLCodeGenerator::write(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070040 this->write(s.c_str());
41}
42
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070043void GLSLCodeGenerator::write(StringFragment s) {
44 if (!s.fLength) {
45 return;
46 }
47 if (fAtLineStart) {
48 for (int i = 0; i < fIndentation; i++) {
49 fOut->writeText(" ");
50 }
51 }
52 fOut->write(s.fChars, s.fLength);
53 fAtLineStart = false;
54}
55
Ethan Nicholas0df1b042017-03-31 13:56:23 -040056void GLSLCodeGenerator::writeLine(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070057 this->writeLine(s.c_str());
58}
59
60void GLSLCodeGenerator::writeLine() {
61 this->writeLine("");
62}
63
Ethan Nicholas88f6d372018-07-27 10:03:46 -040064void GLSLCodeGenerator::writeExtension(const String& name) {
65 this->writeExtension(name, true);
66}
67
68void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
69 fExtensions.writeText("#extension ");
70 fExtensions.write(name.c_str(), name.length());
71 fExtensions.writeText(require ? " : require\n" : " : enable\n");
ethannicholasf789b382016-08-03 12:43:36 -070072}
73
Ethan Nicholasf7b88202017-09-18 14:10:39 -040074bool GLSLCodeGenerator::usesPrecisionModifiers() const {
75 return fProgram.fSettings.fCaps->usesPrecisionModifiers();
76}
77
78String GLSLCodeGenerator::getTypeName(const Type& type) {
79 switch (type.kind()) {
80 case Type::kVector_Kind: {
81 Type component = type.componentType();
82 String result;
83 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
84 result = "vec";
85 }
86 else if (component == *fContext.fDouble_Type) {
87 result = "dvec";
88 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040089 else if (component == *fContext.fInt_Type ||
90 component == *fContext.fShort_Type ||
91 component == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040092 result = "ivec";
93 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040094 else if (component == *fContext.fUInt_Type ||
95 component == *fContext.fUShort_Type ||
96 component == *fContext.fUByte_Type) {
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
ethannicholasf789b382016-08-03 12:43:36 -0700449void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500450 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
451 c.fFunction.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400452 SkASSERT(c.fArguments.size() == 2);
ethannicholas5961bc92016-10-12 06:39:56 -0700453 if (is_abs(*c.fArguments[0])) {
454 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
455 return;
456 }
457 if (is_abs(*c.fArguments[1])) {
458 // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
459 // ever end up mattering, but it's worth calling out.
460 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
461 return;
462 }
463 }
Florin Malita3b30c4f2017-08-08 15:47:35 -0400464 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues() && c.fFunction.fName == "fract" &&
465 c.fFunction.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400466 SkASSERT(c.fArguments.size() == 1);
Florin Malita3b30c4f2017-08-08 15:47:35 -0400467
468 this->write("(0.5 - sign(");
469 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
470 this->write(") * (0.5 - fract(abs(");
471 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
472 this->write("))))");
473
474 return;
475 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500476 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
477 c.fFunction.fName == "atan" &&
478 c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
ethannicholasddb37d62016-10-20 09:54:00 -0700479 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
ethannicholasad146f62016-10-14 06:40:02 -0700480 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
481 if (p.fOperator == Token::MINUS) {
482 this->write("atan(");
483 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
484 this->write(", -1.0 * ");
485 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
486 this->write(")");
487 return;
488 }
489 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500490 if (c.fFunction.fBuiltin && c.fFunction.fName == "determinant" &&
491 fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400492 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500493 this->writeDeterminantHack(*c.fArguments[0]);
494 return;
495 }
496 if (c.fFunction.fBuiltin && c.fFunction.fName == "inverse" &&
497 fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400498 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500499 this->writeInverseHack(*c.fArguments[0]);
500 return;
501 }
502 if (c.fFunction.fBuiltin && c.fFunction.fName == "inverseSqrt" &&
503 fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400504 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500505 this->writeInverseSqrtHack(*c.fArguments[0]);
506 return;
507 }
508 if (c.fFunction.fBuiltin && c.fFunction.fName == "transpose" &&
509 fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400510 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500511 this->writeTransposeHack(*c.fArguments[0]);
512 return;
513 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500514 if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
515 c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400516 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400517 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
ethannicholasddb37d62016-10-20 09:54:00 -0700518 fFoundDerivatives = true;
519 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500520 bool isTextureFunctionWithBias = false;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500521 if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
522 const char* dim = "";
523 bool proj = false;
524 switch (c.fArguments[0]->fType.dimensions()) {
525 case SpvDim1D:
526 dim = "1D";
Brian Osman8a83ca42018-02-12 14:32:17 -0500527 isTextureFunctionWithBias = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500528 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
529 proj = false;
530 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400531 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500532 proj = true;
533 }
534 break;
535 case SpvDim2D:
536 dim = "2D";
Brian Osmanc35d7ea2018-02-21 12:00:14 -0500537 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
538 isTextureFunctionWithBias = true;
539 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400540 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500541 proj = false;
542 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400543 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500544 proj = true;
545 }
546 break;
547 case SpvDim3D:
548 dim = "3D";
Brian Osman8a83ca42018-02-12 14:32:17 -0500549 isTextureFunctionWithBias = true;
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400550 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500551 proj = false;
552 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400553 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500554 proj = true;
555 }
556 break;
557 case SpvDimCube:
558 dim = "Cube";
Brian Osman8a83ca42018-02-12 14:32:17 -0500559 isTextureFunctionWithBias = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500560 proj = false;
561 break;
562 case SpvDimRect:
563 dim = "Rect";
564 proj = false;
565 break;
566 case SpvDimBuffer:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400567 SkASSERT(false); // doesn't exist
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500568 dim = "Buffer";
569 proj = false;
570 break;
571 case SpvDimSubpassData:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400572 SkASSERT(false); // doesn't exist
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500573 dim = "SubpassData";
574 proj = false;
575 break;
576 }
577 this->write("texture");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500578 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500579 this->write(dim);
580 }
581 if (proj) {
582 this->write("Proj");
583 }
584
585 } else {
586 this->write(c.fFunction.fName);
587 }
588 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700589 const char* separator = "";
590 for (const auto& arg : c.fArguments) {
591 this->write(separator);
592 separator = ", ";
593 this->writeExpression(*arg, kSequence_Precedence);
594 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500595 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
596 this->write(", -0.5");
597 }
ethannicholasf789b382016-08-03 12:43:36 -0700598 this->write(")");
599}
600
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400601void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
602 if (c.fArguments.size() == 1 &&
603 this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
604 // in cases like half(float), they're different types as far as SkSL is concerned but the
605 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
606 // out the inner expression here.
607 this->writeExpression(*c.fArguments[0], parentPrecedence);
608 return;
609 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400610 this->writeType(c.fType);
611 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700612 const char* separator = "";
613 for (const auto& arg : c.fArguments) {
614 this->write(separator);
615 separator = ", ";
616 this->writeExpression(*arg, kSequence_Precedence);
617 }
618 this->write(")");
619}
620
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500621void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000622 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500623 if (!fSetupFragCoordWorkaround) {
624 const char* precision = usesPrecisionModifiers() ? "highp " : "";
625 fFunctionHeader += precision;
626 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
627 fFunctionHeader += precision;
628 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
629 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
630 // Ensure that we get exact .5 values for x and y.
631 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
632 "vec2(.5);\n";
633 fSetupFragCoordWorkaround = true;
634 }
635 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000636 return;
637 }
638
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500639 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
640 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
641 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
642 if (!fProgram.fSettings.fFlipY) {
643 this->write("gl_FragCoord");
644 } else if (const char* extension =
645 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
646 if (!fSetupFragPositionGlobal) {
647 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400648 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500649 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400650 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500651 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000652 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500653 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000654 } else {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500655 if (!fSetupFragPositionGlobal) {
656 // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
657 // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
658 // depending on the surrounding code, accessing .xy with a uniform involved can
Brian Osmancd3261a2018-01-16 13:52:29 +0000659 // do the same thing. Copying gl_FragCoord.xy into a temp float2 beforehand
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500660 // (and only accessing .xy) seems to "fix" things.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400661 const char* precision = usesPrecisionModifiers() ? "highp " : "";
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400662 fGlobals.writeText("uniform ");
663 fGlobals.writeText(precision);
664 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500665 fSetupFragPositionGlobal = true;
666 }
667 if (!fSetupFragPositionLocal) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400668 const char* precision = usesPrecisionModifiers() ? "highp " : "";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500669 fFunctionHeader += precision;
670 fFunctionHeader += " vec2 _sktmpCoord = gl_FragCoord.xy;\n";
671 fFunctionHeader += precision;
672 fFunctionHeader += " vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
673 " - _sktmpCoord.y, 1.0, 1.0);\n";
674 fSetupFragPositionLocal = true;
675 }
676 this->write("sk_FragCoord");
677 }
678}
679
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500680void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
681 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
682 case SK_FRAGCOLOR_BUILTIN:
683 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
684 this->write("sk_FragColor");
685 } else {
686 this->write("gl_FragColor");
687 }
688 break;
689 case SK_FRAGCOORD_BUILTIN:
690 this->writeFragCoord();
691 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600692 case SK_CLOCKWISE_BUILTIN:
693 this->write("gl_FrontFacing");
694 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500695 case SK_VERTEXID_BUILTIN:
696 this->write("gl_VertexID");
697 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600698 case SK_INSTANCEID_BUILTIN:
699 this->write("gl_InstanceID");
700 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500701 case SK_CLIPDISTANCE_BUILTIN:
702 this->write("gl_ClipDistance");
703 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500704 case SK_IN_BUILTIN:
705 this->write("gl_in");
706 break;
707 case SK_INVOCATIONID_BUILTIN:
708 this->write("gl_InvocationID");
709 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400710 case SK_LASTFRAGCOLOR_BUILTIN:
711 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
712 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500713 default:
714 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700715 }
ethannicholasf789b382016-08-03 12:43:36 -0700716}
717
718void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
719 this->writeExpression(*expr.fBase, kPostfix_Precedence);
720 this->write("[");
721 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
722 this->write("]");
723}
724
Brian Osmancd3261a2018-01-16 13:52:29 +0000725bool is_sk_position(const FieldAccess& f) {
726 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
727}
728
ethannicholasf789b382016-08-03 12:43:36 -0700729void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
730 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
731 this->writeExpression(*f.fBase, kPostfix_Precedence);
732 this->write(".");
733 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500734 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
735 case SK_CLIPDISTANCE_BUILTIN:
736 this->write("gl_ClipDistance");
737 break;
738 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400739 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
740 if (name == "sk_Position") {
741 this->write("gl_Position");
742 } else if (name == "sk_PointSize") {
743 this->write("gl_PointSize");
744 } else {
745 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
746 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500747 }
ethannicholasf789b382016-08-03 12:43:36 -0700748}
749
750void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
751 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
752 this->write(".");
753 for (int c : swizzle.fComponents) {
754 this->write(&("x\0y\0z\0w\0"[c * 2]));
755 }
756}
757
Ethan Nicholas762466e2017-06-29 10:03:38 -0400758GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -0700759 switch (op) {
760 case Token::STAR: // fall through
761 case Token::SLASH: // fall through
762 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
763 case Token::PLUS: // fall through
764 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
765 case Token::SHL: // fall through
766 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
767 case Token::LT: // fall through
768 case Token::GT: // fall through
769 case Token::LTEQ: // fall through
770 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
771 case Token::EQEQ: // fall through
772 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
773 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
774 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
775 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
776 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
777 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
778 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
779 case Token::EQ: // fall through
780 case Token::PLUSEQ: // fall through
781 case Token::MINUSEQ: // fall through
782 case Token::STAREQ: // fall through
783 case Token::SLASHEQ: // fall through
784 case Token::PERCENTEQ: // fall through
785 case Token::SHLEQ: // fall through
786 case Token::SHREQ: // fall through
787 case Token::LOGICALANDEQ: // fall through
788 case Token::LOGICALXOREQ: // fall through
789 case Token::LOGICALOREQ: // fall through
790 case Token::BITWISEANDEQ: // fall through
791 case Token::BITWISEXOREQ: // fall through
792 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400793 case Token::COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -0700794 default: ABORT("unsupported binary operator");
795 }
796}
797
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400798void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -0700799 Precedence parentPrecedence) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400800 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -0700801 if (precedence >= parentPrecedence) {
802 this->write("(");
803 }
Ethan Nicholas0b631962018-07-24 13:41:11 -0400804 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
805 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +0000806 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
807 is_sk_position((FieldAccess&) *b.fLeft) &&
808 !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
809 !fProgram.fSettings.fCaps->canUseFragCoord();
810 if (positionWorkaround) {
811 this->write("sk_FragCoord_Workaround = (");
812 }
ethannicholasf789b382016-08-03 12:43:36 -0700813 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700814 this->write(" ");
815 this->write(Compiler::OperatorName(b.fOperator));
816 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -0700817 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +0000818 if (positionWorkaround) {
819 this->write(")");
820 }
ethannicholasf789b382016-08-03 12:43:36 -0700821 if (precedence >= parentPrecedence) {
822 this->write(")");
823 }
824}
825
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400826void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -0700827 Precedence parentPrecedence) {
828 if (kTernary_Precedence >= parentPrecedence) {
829 this->write("(");
830 }
831 this->writeExpression(*t.fTest, kTernary_Precedence);
832 this->write(" ? ");
833 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
834 this->write(" : ");
835 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
836 if (kTernary_Precedence >= parentPrecedence) {
837 this->write(")");
838 }
839}
840
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400841void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700842 Precedence parentPrecedence) {
843 if (kPrefix_Precedence >= parentPrecedence) {
844 this->write("(");
845 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700846 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700847 this->writeExpression(*p.fOperand, kPrefix_Precedence);
848 if (kPrefix_Precedence >= parentPrecedence) {
849 this->write(")");
850 }
851}
852
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400853void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700854 Precedence parentPrecedence) {
855 if (kPostfix_Precedence >= parentPrecedence) {
856 this->write("(");
857 }
858 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700859 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700860 if (kPostfix_Precedence >= parentPrecedence) {
861 this->write(")");
862 }
863}
864
865void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
866 this->write(b.fValue ? "true" : "false");
867}
868
869void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -0700870 if (i.fType == *fContext.fUInt_Type) {
871 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -0500872 } else if (i.fType == *fContext.fUShort_Type) {
873 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400874 } else if (i.fType == *fContext.fUByte_Type) {
875 this->write(to_string(i.fValue & 0xff) + "u");
876 } else {
ethannicholas5961bc92016-10-12 06:39:56 -0700877 this->write(to_string((int32_t) i.fValue));
878 }
ethannicholasf789b382016-08-03 12:43:36 -0700879}
880
881void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
882 this->write(to_string(f.fValue));
883}
884
Ethan Nicholas762466e2017-06-29 10:03:38 -0400885void GLSLCodeGenerator::writeSetting(const Setting& s) {
886 ABORT("internal error; setting was not folded to a constant during compilation\n");
887}
888
ethannicholasf789b382016-08-03 12:43:36 -0700889void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholas00543112018-07-31 09:44:36 -0400890 if (fProgramKind != Program::kPipelineStage_Kind) {
891 this->writeTypePrecision(f.fDeclaration.fReturnType);
892 this->writeType(f.fDeclaration.fReturnType);
893 this->write(" " + f.fDeclaration.fName + "(");
894 const char* separator = "";
895 for (const auto& param : f.fDeclaration.fParameters) {
896 this->write(separator);
897 separator = ", ";
898 this->writeModifiers(param->fModifiers, false);
899 std::vector<int> sizes;
900 const Type* type = &param->fType;
901 while (type->kind() == Type::kArray_Kind) {
902 sizes.push_back(type->columns());
903 type = &type->componentType();
904 }
905 this->writeTypePrecision(*type);
906 this->writeType(*type);
907 this->write(" " + param->fName);
908 for (int s : sizes) {
909 if (s <= 0) {
910 this->write("[]");
911 } else {
912 this->write("[" + to_string(s) + "]");
913 }
ethannicholas5961bc92016-10-12 06:39:56 -0700914 }
915 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400916 this->writeLine(") {");
917 fIndentation++;
ethannicholasf789b382016-08-03 12:43:36 -0700918 }
ethannicholas5961bc92016-10-12 06:39:56 -0700919 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400920 OutputStream* oldOut = fOut;
921 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -0700922 fOut = &buffer;
Ethan Nicholascb670962017-04-20 19:31:52 -0400923 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas00543112018-07-31 09:44:36 -0400924 if (fProgramKind != Program::kPipelineStage_Kind) {
925 fIndentation--;
926 this->writeLine("}");
927 }
ethannicholas5961bc92016-10-12 06:39:56 -0700928
929 fOut = oldOut;
930 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400931 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -0700932}
933
Greg Daniel64773e62016-11-22 09:44:03 -0500934void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -0700935 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -0500936 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
937 this->write("flat ");
938 }
ethannicholas5961bc92016-10-12 06:39:56 -0700939 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
940 this->write("noperspective ");
941 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400942 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -0500943 if (layout.size()) {
944 this->write(layout + " ");
945 }
Brian Salomonf9f45122016-11-29 11:59:17 -0500946 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
947 this->write("readonly ");
948 }
949 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
950 this->write("writeonly ");
951 }
952 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
953 this->write("coherent ");
954 }
955 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
956 this->write("volatile ");
957 }
958 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
959 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -0700960 }
Greg Daniel64773e62016-11-22 09:44:03 -0500961 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -0700962 (modifiers.fFlags & Modifiers::kOut_Flag)) {
963 this->write("inout ");
964 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500965 if (globalContext &&
966 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700967 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
968 : "varying ");
969 } else {
970 this->write("in ");
971 }
972 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500973 if (globalContext &&
974 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700975 this->write("varying ");
976 } else {
977 this->write("out ");
978 }
979 }
980 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
981 this->write("uniform ");
982 }
983 if (modifiers.fFlags & Modifiers::kConst_Flag) {
984 this->write("const ");
985 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400986 if (usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700987 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
988 this->write("lowp ");
989 }
990 if (modifiers.fFlags & Modifiers::kMediump_Flag) {
991 this->write("mediump ");
992 }
993 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
994 this->write("highp ");
995 }
996 }
ethannicholasf789b382016-08-03 12:43:36 -0700997}
998
999void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001000 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001001 return;
1002 }
ethannicholas5961bc92016-10-12 06:39:56 -07001003 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001004 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001005 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001006 const Type* structType = &intf.fVariable.fType;
1007 while (structType->kind() == Type::kArray_Kind) {
1008 structType = &structType->componentType();
1009 }
1010 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001011 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001012 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001013 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001014 this->writeLine(" " + f.fName + ";");
1015 }
1016 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001017 this->write("}");
1018 if (intf.fInstanceName.size()) {
1019 this->write(" ");
1020 this->write(intf.fInstanceName);
1021 for (const auto& size : intf.fSizes) {
1022 this->write("[");
1023 if (size) {
1024 this->writeExpression(*size, kTopLevel_Precedence);
1025 }
1026 this->write("]");
1027 }
1028 }
1029 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001030}
1031
Ethan Nicholas762466e2017-06-29 10:03:38 -04001032void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1033 this->writeExpression(value, kTopLevel_Precedence);
1034}
1035
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001036const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1037 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001038 switch (type.kind()) {
1039 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001040 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1041 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001042 if (fProgram.fSettings.fForceHighPrecision ||
1043 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1044 return "highp ";
1045 }
1046 return "mediump ";
1047 }
1048 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001049 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001050 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001051 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1052 type == *fContext.fUInt_Type) {
1053 return "highp ";
1054 }
1055 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001056 case Type::kVector_Kind: // fall through
1057 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001058 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001059 default:
1060 break;
1061 }
1062 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001063 return "";
1064}
1065
1066void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1067 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001068}
1069
ethannicholas5961bc92016-10-12 06:39:56 -07001070void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001071 if (!decl.fVars.size()) {
1072 return;
1073 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001074 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001075 for (const auto& stmt : decl.fVars) {
1076 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001077 if (wroteType) {
1078 this->write(", ");
1079 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001080 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001081 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001082 this->writeType(decl.fBaseType);
1083 this->write(" ");
1084 wroteType = true;
1085 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001086 this->write(var.fVar->fName);
1087 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001088 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001089 if (size) {
1090 this->writeExpression(*size, kTopLevel_Precedence);
1091 }
ethannicholasf789b382016-08-03 12:43:36 -07001092 this->write("]");
1093 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001094 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001095 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001096 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001097 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001098 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001099 if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001100 this->writeExtension(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
Brian Salomon2a51de82016-11-16 12:06:01 -05001101 }
1102 fFoundImageDecl = true;
1103 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001104 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1105 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001106 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001107 }
Brian Osman061020e2018-04-17 14:22:15 -04001108 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001109 this->writeExtension(
1110 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001111 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001112 fFoundExternalSamplerDecl = true;
1113 }
ethannicholasf789b382016-08-03 12:43:36 -07001114 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001115 if (wroteType) {
1116 this->write(";");
1117 }
ethannicholasf789b382016-08-03 12:43:36 -07001118}
1119
1120void GLSLCodeGenerator::writeStatement(const Statement& s) {
1121 switch (s.fKind) {
1122 case Statement::kBlock_Kind:
1123 this->writeBlock((Block&) s);
1124 break;
1125 case Statement::kExpression_Kind:
1126 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1127 this->write(";");
1128 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001129 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001130 this->writeReturnStatement((ReturnStatement&) s);
1131 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001132 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001133 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001134 break;
1135 case Statement::kIf_Kind:
1136 this->writeIfStatement((IfStatement&) s);
1137 break;
1138 case Statement::kFor_Kind:
1139 this->writeForStatement((ForStatement&) s);
1140 break;
1141 case Statement::kWhile_Kind:
1142 this->writeWhileStatement((WhileStatement&) s);
1143 break;
1144 case Statement::kDo_Kind:
1145 this->writeDoStatement((DoStatement&) s);
1146 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001147 case Statement::kSwitch_Kind:
1148 this->writeSwitchStatement((SwitchStatement&) s);
1149 break;
ethannicholasf789b382016-08-03 12:43:36 -07001150 case Statement::kBreak_Kind:
1151 this->write("break;");
1152 break;
1153 case Statement::kContinue_Kind:
1154 this->write("continue;");
1155 break;
1156 case Statement::kDiscard_Kind:
1157 this->write("discard;");
1158 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001159 case Statement::kNop_Kind:
1160 this->write(";");
1161 break;
ethannicholasf789b382016-08-03 12:43:36 -07001162 default:
1163 ABORT("unsupported statement: %s", s.description().c_str());
1164 }
1165}
1166
Ethan Nicholascb670962017-04-20 19:31:52 -04001167void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1168 for (const auto& s : statements) {
1169 if (!s->isEmpty()) {
1170 this->writeStatement(*s);
1171 this->writeLine();
1172 }
1173 }
1174}
1175
ethannicholasf789b382016-08-03 12:43:36 -07001176void GLSLCodeGenerator::writeBlock(const Block& b) {
1177 this->writeLine("{");
1178 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001179 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001180 fIndentation--;
1181 this->write("}");
1182}
1183
1184void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1185 this->write("if (");
1186 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1187 this->write(") ");
1188 this->writeStatement(*stmt.fIfTrue);
1189 if (stmt.fIfFalse) {
1190 this->write(" else ");
1191 this->writeStatement(*stmt.fIfFalse);
1192 }
1193}
1194
1195void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1196 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001197 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001198 this->writeStatement(*f.fInitializer);
1199 } else {
1200 this->write("; ");
1201 }
1202 if (f.fTest) {
1203 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1204 }
1205 this->write("; ");
1206 if (f.fNext) {
1207 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1208 }
1209 this->write(") ");
1210 this->writeStatement(*f.fStatement);
1211}
1212
1213void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1214 this->write("while (");
1215 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1216 this->write(") ");
1217 this->writeStatement(*w.fStatement);
1218}
1219
1220void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1221 this->write("do ");
1222 this->writeStatement(*d.fStatement);
1223 this->write(" while (");
1224 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1225 this->write(");");
1226}
1227
Ethan Nicholasaf197692017-02-27 13:26:45 -05001228void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1229 this->write("switch (");
1230 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1231 this->writeLine(") {");
1232 fIndentation++;
1233 for (const auto& c : s.fCases) {
1234 if (c->fValue) {
1235 this->write("case ");
1236 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1237 this->writeLine(":");
1238 } else {
1239 this->writeLine("default:");
1240 }
1241 fIndentation++;
1242 for (const auto& stmt : c->fStatements) {
1243 this->writeStatement(*stmt);
1244 this->writeLine();
1245 }
1246 fIndentation--;
1247 }
1248 fIndentation--;
1249 this->write("}");
1250}
1251
ethannicholasf789b382016-08-03 12:43:36 -07001252void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1253 this->write("return");
1254 if (r.fExpression) {
1255 this->write(" ");
1256 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1257 }
1258 this->write(";");
1259}
1260
Ethan Nicholas762466e2017-06-29 10:03:38 -04001261void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001262 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001263 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001264}
1265
Ethan Nicholas762466e2017-06-29 10:03:38 -04001266void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1267 switch (e.fKind) {
1268 case ProgramElement::kExtension_Kind:
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001269 this->writeExtension(((Extension&) e).fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001270 break;
1271 case ProgramElement::kVar_Kind: {
1272 VarDeclarations& decl = (VarDeclarations&) e;
1273 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001274 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001275 if (builtin == -1) {
1276 // normal var
1277 this->writeVarDeclarations(decl, true);
1278 this->writeLine();
1279 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1280 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
Brian Salomondc092132018-04-04 10:14:16 -04001281 if (fProgram.fSettings.fFragColorIsInOut) {
1282 this->write("inout ");
1283 } else {
1284 this->write("out ");
1285 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001286 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001287 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001288 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001289 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001290 }
Mike Klein5ce39722017-06-27 22:52:03 +00001291 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001292 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001293 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001294 case ProgramElement::kInterfaceBlock_Kind:
1295 this->writeInterfaceBlock((InterfaceBlock&) e);
1296 break;
1297 case ProgramElement::kFunction_Kind:
1298 this->writeFunction((FunctionDefinition&) e);
1299 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001300 case ProgramElement::kModifiers_Kind: {
1301 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1302 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1303 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001304 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001305 }
1306 fFoundGSInvocations = true;
1307 }
1308 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001309 this->writeLine(";");
1310 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001311 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001312 case ProgramElement::kEnum_Kind:
1313 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001314 default:
1315 printf("%s\n", e.description().c_str());
1316 ABORT("unsupported program element");
Ethan Nicholasc0709392017-06-27 11:20:22 -04001317 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001318}
1319
1320bool GLSLCodeGenerator::generateCode() {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001321 fProgramKind = fProgram.fKind;
Ethan Nicholas00543112018-07-31 09:44:36 -04001322 if (fProgramKind != Program::kPipelineStage_Kind) {
1323 this->writeHeader();
1324 }
Chris Dalton8fd79552018-01-11 00:46:14 -05001325 if (Program::kGeometry_Kind == fProgramKind &&
1326 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001327 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001328 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001329 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001330 StringStream body;
1331 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001332 for (const auto& e : fProgram) {
1333 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001334 }
1335 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001336
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001337 write_stringstream(fExtensions, *rawOut);
1338 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001339
1340 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1341 Layout layout;
1342 switch (fProgram.fKind) {
1343 case Program::kVertex_Kind: {
1344 Modifiers modifiers(layout, Modifiers::kOut_Flag | Modifiers::kHighp_Flag);
1345 this->writeModifiers(modifiers, true);
1346 this->write("vec4 sk_FragCoord_Workaround;\n");
1347 break;
1348 }
1349 case Program::kFragment_Kind: {
1350 Modifiers modifiers(layout, Modifiers::kIn_Flag | Modifiers::kHighp_Flag);
1351 this->writeModifiers(modifiers, true);
1352 this->write("vec4 sk_FragCoord_Workaround;\n");
1353 break;
1354 }
1355 default:
1356 break;
1357 }
1358 }
1359
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001360 if (this->usesPrecisionModifiers()) {
1361 this->writeLine("precision mediump float;");
1362 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001363 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001364 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001365 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001366}
1367
1368}