blob: 87662609406758ae2a4b9956d6877c83c0bdd13d [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
64void GLSLCodeGenerator::writeExtension(const Extension& ext) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070065 this->write("#extension ");
66 this->write(ext.fName);
67 this->writeLine(" : enable");
ethannicholasf789b382016-08-03 12:43:36 -070068}
69
Ethan Nicholasf7b88202017-09-18 14:10:39 -040070bool GLSLCodeGenerator::usesPrecisionModifiers() const {
71 return fProgram.fSettings.fCaps->usesPrecisionModifiers();
72}
73
74String GLSLCodeGenerator::getTypeName(const Type& type) {
75 switch (type.kind()) {
76 case Type::kVector_Kind: {
77 Type component = type.componentType();
78 String result;
79 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
80 result = "vec";
81 }
82 else if (component == *fContext.fDouble_Type) {
83 result = "dvec";
84 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040085 else if (component == *fContext.fInt_Type ||
86 component == *fContext.fShort_Type ||
87 component == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040088 result = "ivec";
89 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -040090 else if (component == *fContext.fUInt_Type ||
91 component == *fContext.fUShort_Type ||
92 component == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040093 result = "uvec";
94 }
95 else if (component == *fContext.fBool_Type) {
96 result = "bvec";
97 }
98 else {
99 ABORT("unsupported vector type");
100 }
101 result += to_string(type.columns());
102 return result;
103 }
104 case Type::kMatrix_Kind: {
105 String result;
106 Type component = type.componentType();
107 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
108 result = "mat";
109 }
110 else if (component == *fContext.fDouble_Type) {
111 result = "dmat";
112 }
113 else {
114 ABORT("unsupported matrix type");
115 }
116 result += to_string(type.columns());
117 if (type.columns() != type.rows()) {
118 result += "x";
119 result += to_string(type.rows());
120 }
121 return result;
122 }
123 case Type::kArray_Kind: {
124 String result = this->getTypeName(type.componentType()) + "[";
125 if (type.columns() != -1) {
126 result += to_string(type.columns());
127 }
128 result += "]";
129 return result;
130 }
131 case Type::kScalar_Kind: {
132 if (type == *fContext.fHalf_Type) {
133 return "float";
134 }
135 else if (type == *fContext.fShort_Type) {
136 return "int";
137 }
138 else if (type == *fContext.fUShort_Type) {
139 return "uint";
140 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400141 else if (type == *fContext.fByte_Type) {
142 return "int";
143 }
144 else if (type == *fContext.fUByte_Type) {
145 return "uint";
146 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400147 else {
148 return type.name();
149 }
150 break;
151 }
152 default:
153 return type.name();
154 }
155}
156
ethannicholasf789b382016-08-03 12:43:36 -0700157void GLSLCodeGenerator::writeType(const Type& type) {
158 if (type.kind() == Type::kStruct_Kind) {
159 for (const Type* search : fWrittenStructs) {
160 if (*search == type) {
161 // already written
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700162 this->write(type.fName);
ethannicholasf789b382016-08-03 12:43:36 -0700163 return;
164 }
165 }
166 fWrittenStructs.push_back(&type);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700167 this->write("struct ");
168 this->write(type.fName);
169 this->writeLine(" {");
ethannicholasf789b382016-08-03 12:43:36 -0700170 fIndentation++;
171 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700172 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400173 this->writeTypePrecision(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700174 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -0700175 this->writeType(*f.fType);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700176 this->write(" ");
177 this->write(f.fName);
178 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -0700179 }
180 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -0500181 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -0700182 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400183 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700184 }
185}
186
187void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
188 switch (expr.fKind) {
189 case Expression::kBinary_Kind:
190 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
191 break;
192 case Expression::kBoolLiteral_Kind:
193 this->writeBoolLiteral((BoolLiteral&) expr);
194 break;
195 case Expression::kConstructor_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400196 this->writeConstructor((Constructor&) expr, parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700197 break;
198 case Expression::kIntLiteral_Kind:
199 this->writeIntLiteral((IntLiteral&) expr);
200 break;
201 case Expression::kFieldAccess_Kind:
202 this->writeFieldAccess(((FieldAccess&) expr));
203 break;
204 case Expression::kFloatLiteral_Kind:
205 this->writeFloatLiteral(((FloatLiteral&) expr));
206 break;
207 case Expression::kFunctionCall_Kind:
208 this->writeFunctionCall((FunctionCall&) expr);
209 break;
210 case Expression::kPrefix_Kind:
211 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
212 break;
213 case Expression::kPostfix_Kind:
214 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
215 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -0400216 case Expression::kSetting_Kind:
217 this->writeSetting((Setting&) expr);
218 break;
ethannicholasf789b382016-08-03 12:43:36 -0700219 case Expression::kSwizzle_Kind:
220 this->writeSwizzle((Swizzle&) expr);
221 break;
222 case Expression::kVariableReference_Kind:
223 this->writeVariableReference((VariableReference&) expr);
224 break;
225 case Expression::kTernary_Kind:
226 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
227 break;
228 case Expression::kIndex_Kind:
229 this->writeIndexExpression((IndexExpression&) expr);
230 break;
231 default:
232 ABORT("unsupported expression: %s", expr.description().c_str());
233 }
234}
235
ethannicholas5961bc92016-10-12 06:39:56 -0700236static bool is_abs(Expression& expr) {
237 if (expr.fKind != Expression::kFunctionCall_Kind) {
238 return false;
239 }
240 return ((FunctionCall&) expr).fFunction.fName == "abs";
241}
242
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500243// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700244// Tegra3 compiler bug.
245void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400246 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400247 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
248 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400249 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.fType) +
250 this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
251 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.fType) +
252 this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700253 this->write("((" + tmpVar1 + " = ");
254 this->writeExpression(absExpr, kTopLevel_Precedence);
255 this->write(") < (" + tmpVar2 + " = ");
256 this->writeExpression(otherExpr, kAssignment_Precedence);
257 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
258}
259
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500260void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
261 this->write("(1.0 / sqrt(");
262 this->writeExpression(x, kTopLevel_Precedence);
263 this->write("))");
264}
265
266void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
267 String name;
268 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
269 name = "_determinant2";
270 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
271 fWrittenIntrinsics.insert(name);
272 fExtraFunctions.writeText((
273 "float " + name + "(mat2 m) {"
274 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
275 "}"
276 ).c_str());
277 }
278 }
279 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
280 name = "_determinant3";
281 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
282 fWrittenIntrinsics.insert(name);
283 fExtraFunctions.writeText((
284 "float " + name + "(mat3 m) {"
285 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
286 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
287 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
288 " float b01 = a22 * a11 - a12 * a21;"
289 " float b11 = -a22 * a10 + a12 * a20;"
290 " float b21 = a21 * a10 - a11 * a20;"
291 " return a00 * b01 + a01 * b11 + a02 * b21;"
292 "}"
293 ).c_str());
294 }
295 }
296 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
297 name = "_determinant3";
298 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
299 fWrittenIntrinsics.insert(name);
300 fExtraFunctions.writeText((
301 "mat4 " + name + "(mat4 m) {"
302 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
303 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
304 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
305 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
306 " float b00 = a00 * a11 - a01 * a10;"
307 " float b01 = a00 * a12 - a02 * a10;"
308 " float b02 = a00 * a13 - a03 * a10;"
309 " float b03 = a01 * a12 - a02 * a11;"
310 " float b04 = a01 * a13 - a03 * a11;"
311 " float b05 = a02 * a13 - a03 * a12;"
312 " float b06 = a20 * a31 - a21 * a30;"
313 " float b07 = a20 * a32 - a22 * a30;"
314 " float b08 = a20 * a33 - a23 * a30;"
315 " float b09 = a21 * a32 - a22 * a31;"
316 " float b10 = a21 * a33 - a23 * a31;"
317 " float b11 = a22 * a33 - a23 * a32;"
318 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
319 "}"
320 ).c_str());
321 }
322 }
323 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400324 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500325 }
326 this->write(name + "(");
327 this->writeExpression(mat, kTopLevel_Precedence);
328 this->write(")");
329}
330
331void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
332 String name;
333 if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
334 name = "_inverse2";
335 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
336 fWrittenIntrinsics.insert(name);
337 fExtraFunctions.writeText((
338 "mat2 " + name + "(mat2 m) {"
339 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
340 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
341 "}"
342 ).c_str());
343 }
344 }
345 else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
346 name = "_inverse3";
347 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
348 fWrittenIntrinsics.insert(name);
349 fExtraFunctions.writeText((
350 "mat3 " + name + "(mat3 m) {"
351 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
352 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
353 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
354 " float b01 = a22 * a11 - a12 * a21;"
355 " float b11 = -a22 * a10 + a12 * a20;"
356 " float b21 = a21 * a10 - a11 * a20;"
357 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
358 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
359 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
360 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
361 "}"
362 ).c_str());
363 }
364 }
365 else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
366 name = "_inverse4";
367 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
368 fWrittenIntrinsics.insert(name);
369 fExtraFunctions.writeText((
370 "mat4 " + name + "(mat4 m) {"
371 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
372 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
373 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
374 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
375 " float b00 = a00 * a11 - a01 * a10;"
376 " float b01 = a00 * a12 - a02 * a10;"
377 " float b02 = a00 * a13 - a03 * a10;"
378 " float b03 = a01 * a12 - a02 * a11;"
379 " float b04 = a01 * a13 - a03 * a11;"
380 " float b05 = a02 * a13 - a03 * a12;"
381 " float b06 = a20 * a31 - a21 * a30;"
382 " float b07 = a20 * a32 - a22 * a30;"
383 " float b08 = a20 * a33 - a23 * a30;"
384 " float b09 = a21 * a32 - a22 * a31;"
385 " float b10 = a21 * a33 - a23 * a31;"
386 " float b11 = a22 * a33 - a23 * a32;"
387 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
388 " b04 * b07 + b05 * b06;"
389 " return mat4("
390 " a11 * b11 - a12 * b10 + a13 * b09,"
391 " a02 * b10 - a01 * b11 - a03 * b09,"
392 " a31 * b05 - a32 * b04 + a33 * b03,"
393 " a22 * b04 - a21 * b05 - a23 * b03,"
394 " a12 * b08 - a10 * b11 - a13 * b07,"
395 " a00 * b11 - a02 * b08 + a03 * b07,"
396 " a32 * b02 - a30 * b05 - a33 * b01,"
397 " a20 * b05 - a22 * b02 + a23 * b01,"
398 " a10 * b10 - a11 * b08 + a13 * b06,"
399 " a01 * b08 - a00 * b10 - a03 * b06,"
400 " a30 * b04 - a31 * b02 + a33 * b00,"
401 " a21 * b02 - a20 * b04 - a23 * b00,"
402 " a11 * b07 - a10 * b09 - a12 * b06,"
403 " a00 * b09 - a01 * b07 + a02 * b06,"
404 " a31 * b01 - a30 * b03 - a32 * b00,"
405 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
406 "}"
407 ).c_str());
408 }
409 }
410 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400411 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500412 }
413 this->write(name + "(");
414 this->writeExpression(mat, kTopLevel_Precedence);
415 this->write(")");
416}
417
418void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
419 String name = "transpose" + to_string(mat.fType.columns()) + to_string(mat.fType.rows());
420 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
421 fWrittenIntrinsics.insert(name);
422 String type = this->getTypeName(mat.fType);
423 const Type& base = mat.fType.componentType();
424 String transposed = this->getTypeName(base.toCompound(fContext,
425 mat.fType.rows(),
426 mat.fType.columns()));
427 fExtraFunctions.writeText((transposed + " " + name + "(" + type + " m) {\nreturn " +
428 transposed + "(").c_str());
429 const char* separator = "";
430 for (int row = 0; row < mat.fType.rows(); ++row) {
431 for (int column = 0; column < mat.fType.columns(); ++column) {
432 fExtraFunctions.writeText(separator);
433 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
434 "]").c_str());
435 separator = ", ";
436 }
437 }
438 fExtraFunctions.writeText("); }");
439 }
440 this->write(name + "(");
441 this->writeExpression(mat, kTopLevel_Precedence);
442 this->write(")");
443}
444
ethannicholasf789b382016-08-03 12:43:36 -0700445void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500446 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
447 c.fFunction.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400448 SkASSERT(c.fArguments.size() == 2);
ethannicholas5961bc92016-10-12 06:39:56 -0700449 if (is_abs(*c.fArguments[0])) {
450 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
451 return;
452 }
453 if (is_abs(*c.fArguments[1])) {
454 // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
455 // ever end up mattering, but it's worth calling out.
456 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
457 return;
458 }
459 }
Florin Malita3b30c4f2017-08-08 15:47:35 -0400460 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues() && c.fFunction.fName == "fract" &&
461 c.fFunction.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400462 SkASSERT(c.fArguments.size() == 1);
Florin Malita3b30c4f2017-08-08 15:47:35 -0400463
464 this->write("(0.5 - sign(");
465 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
466 this->write(") * (0.5 - fract(abs(");
467 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
468 this->write("))))");
469
470 return;
471 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500472 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
473 c.fFunction.fName == "atan" &&
474 c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
ethannicholasddb37d62016-10-20 09:54:00 -0700475 c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
ethannicholasad146f62016-10-14 06:40:02 -0700476 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
477 if (p.fOperator == Token::MINUS) {
478 this->write("atan(");
479 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
480 this->write(", -1.0 * ");
481 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
482 this->write(")");
483 return;
484 }
485 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500486 if (c.fFunction.fBuiltin && c.fFunction.fName == "determinant" &&
487 fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400488 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500489 this->writeDeterminantHack(*c.fArguments[0]);
490 return;
491 }
492 if (c.fFunction.fBuiltin && c.fFunction.fName == "inverse" &&
493 fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400494 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500495 this->writeInverseHack(*c.fArguments[0]);
496 return;
497 }
498 if (c.fFunction.fBuiltin && c.fFunction.fName == "inverseSqrt" &&
499 fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400500 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500501 this->writeInverseSqrtHack(*c.fArguments[0]);
502 return;
503 }
504 if (c.fFunction.fBuiltin && c.fFunction.fName == "transpose" &&
505 fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400506 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500507 this->writeTransposeHack(*c.fArguments[0]);
508 return;
509 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500510 if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
511 c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400512 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500513 fHeader.writeText("#extension ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500514 fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500515 fHeader.writeText(" : require\n");
ethannicholasddb37d62016-10-20 09:54:00 -0700516 fFoundDerivatives = true;
517 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500518 bool isTextureFunctionWithBias = false;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500519 if (c.fFunction.fName == "texture" && c.fFunction.fBuiltin) {
520 const char* dim = "";
521 bool proj = false;
522 switch (c.fArguments[0]->fType.dimensions()) {
523 case SpvDim1D:
524 dim = "1D";
Brian Osman8a83ca42018-02-12 14:32:17 -0500525 isTextureFunctionWithBias = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500526 if (c.fArguments[1]->fType == *fContext.fFloat_Type) {
527 proj = false;
528 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400529 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500530 proj = true;
531 }
532 break;
533 case SpvDim2D:
534 dim = "2D";
Brian Osmanc35d7ea2018-02-21 12:00:14 -0500535 if (c.fArguments[0]->fType != *fContext.fSamplerExternalOES_Type) {
536 isTextureFunctionWithBias = true;
537 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400538 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500539 proj = false;
540 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400541 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500542 proj = true;
543 }
544 break;
545 case SpvDim3D:
546 dim = "3D";
Brian Osman8a83ca42018-02-12 14:32:17 -0500547 isTextureFunctionWithBias = true;
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400548 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500549 proj = false;
550 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400551 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat4_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500552 proj = true;
553 }
554 break;
555 case SpvDimCube:
556 dim = "Cube";
Brian Osman8a83ca42018-02-12 14:32:17 -0500557 isTextureFunctionWithBias = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500558 proj = false;
559 break;
560 case SpvDimRect:
561 dim = "Rect";
562 proj = false;
563 break;
564 case SpvDimBuffer:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400565 SkASSERT(false); // doesn't exist
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500566 dim = "Buffer";
567 proj = false;
568 break;
569 case SpvDimSubpassData:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400570 SkASSERT(false); // doesn't exist
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500571 dim = "SubpassData";
572 proj = false;
573 break;
574 }
575 this->write("texture");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500576 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500577 this->write(dim);
578 }
579 if (proj) {
580 this->write("Proj");
581 }
582
583 } else {
584 this->write(c.fFunction.fName);
585 }
586 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700587 const char* separator = "";
588 for (const auto& arg : c.fArguments) {
589 this->write(separator);
590 separator = ", ";
591 this->writeExpression(*arg, kSequence_Precedence);
592 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500593 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
594 this->write(", -0.5");
595 }
ethannicholasf789b382016-08-03 12:43:36 -0700596 this->write(")");
597}
598
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400599void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
600 if (c.fArguments.size() == 1 &&
601 this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
602 // in cases like half(float), they're different types as far as SkSL is concerned but the
603 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
604 // out the inner expression here.
605 this->writeExpression(*c.fArguments[0], parentPrecedence);
606 return;
607 }
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400608 this->writeType(c.fType);
609 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700610 const char* separator = "";
611 for (const auto& arg : c.fArguments) {
612 this->write(separator);
613 separator = ", ";
614 this->writeExpression(*arg, kSequence_Precedence);
615 }
616 this->write(")");
617}
618
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500619void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000620 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500621 if (!fSetupFragCoordWorkaround) {
622 const char* precision = usesPrecisionModifiers() ? "highp " : "";
623 fFunctionHeader += precision;
624 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
625 fFunctionHeader += precision;
626 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
627 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
628 // Ensure that we get exact .5 values for x and y.
629 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
630 "vec2(.5);\n";
631 fSetupFragCoordWorkaround = true;
632 }
633 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000634 return;
635 }
636
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500637 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
638 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
639 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
640 if (!fProgram.fSettings.fFlipY) {
641 this->write("gl_FragCoord");
642 } else if (const char* extension =
643 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
644 if (!fSetupFragPositionGlobal) {
645 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
646 fHeader.writeText("#extension ");
647 fHeader.writeText(extension);
648 fHeader.writeText(" : require\n");
649 }
650 fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
651 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 Nicholas941e7e22016-12-12 15:33:30 -0500662 fHeader.writeText("uniform ");
663 fHeader.writeText(precision);
664 fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
665 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;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500692 case SK_VERTEXID_BUILTIN:
693 this->write("gl_VertexID");
694 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600695 case SK_INSTANCEID_BUILTIN:
696 this->write("gl_InstanceID");
697 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500698 case SK_CLIPDISTANCE_BUILTIN:
699 this->write("gl_ClipDistance");
700 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500701 case SK_IN_BUILTIN:
702 this->write("gl_in");
703 break;
704 case SK_INVOCATIONID_BUILTIN:
705 this->write("gl_InvocationID");
706 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400707 case SK_LASTFRAGCOLOR_BUILTIN:
708 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
709 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500710 default:
711 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700712 }
ethannicholasf789b382016-08-03 12:43:36 -0700713}
714
715void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
716 this->writeExpression(*expr.fBase, kPostfix_Precedence);
717 this->write("[");
718 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
719 this->write("]");
720}
721
Brian Osmancd3261a2018-01-16 13:52:29 +0000722bool is_sk_position(const FieldAccess& f) {
723 return "sk_Position" == f.fBase->fType.fields()[f.fFieldIndex].fName;
724}
725
ethannicholasf789b382016-08-03 12:43:36 -0700726void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
727 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
728 this->writeExpression(*f.fBase, kPostfix_Precedence);
729 this->write(".");
730 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500731 switch (f.fBase->fType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
732 case SK_CLIPDISTANCE_BUILTIN:
733 this->write("gl_ClipDistance");
734 break;
735 default:
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400736 StringFragment name = f.fBase->fType.fields()[f.fFieldIndex].fName;
737 if (name == "sk_Position") {
738 this->write("gl_Position");
739 } else if (name == "sk_PointSize") {
740 this->write("gl_PointSize");
741 } else {
742 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
743 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500744 }
ethannicholasf789b382016-08-03 12:43:36 -0700745}
746
747void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
748 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
749 this->write(".");
750 for (int c : swizzle.fComponents) {
751 this->write(&("x\0y\0z\0w\0"[c * 2]));
752 }
753}
754
Ethan Nicholas762466e2017-06-29 10:03:38 -0400755GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -0700756 switch (op) {
757 case Token::STAR: // fall through
758 case Token::SLASH: // fall through
759 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
760 case Token::PLUS: // fall through
761 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
762 case Token::SHL: // fall through
763 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
764 case Token::LT: // fall through
765 case Token::GT: // fall through
766 case Token::LTEQ: // fall through
767 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
768 case Token::EQEQ: // fall through
769 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
770 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
771 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
772 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
773 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
774 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
775 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
776 case Token::EQ: // fall through
777 case Token::PLUSEQ: // fall through
778 case Token::MINUSEQ: // fall through
779 case Token::STAREQ: // fall through
780 case Token::SLASHEQ: // fall through
781 case Token::PERCENTEQ: // fall through
782 case Token::SHLEQ: // fall through
783 case Token::SHREQ: // fall through
784 case Token::LOGICALANDEQ: // fall through
785 case Token::LOGICALXOREQ: // fall through
786 case Token::LOGICALOREQ: // fall through
787 case Token::BITWISEANDEQ: // fall through
788 case Token::BITWISEXOREQ: // fall through
789 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400790 case Token::COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -0700791 default: ABORT("unsupported binary operator");
792 }
793}
794
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400795void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -0700796 Precedence parentPrecedence) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400797 Precedence precedence = GetBinaryPrecedence(b.fOperator);
ethannicholasf789b382016-08-03 12:43:36 -0700798 if (precedence >= parentPrecedence) {
799 this->write("(");
800 }
Ethan Nicholas0b631962018-07-24 13:41:11 -0400801 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
802 Compiler::IsAssignment(b.fOperator) &&
Brian Osmancd3261a2018-01-16 13:52:29 +0000803 Expression::kFieldAccess_Kind == b.fLeft->fKind &&
804 is_sk_position((FieldAccess&) *b.fLeft) &&
805 !strstr(b.fRight->description().c_str(), "sk_RTAdjust") &&
806 !fProgram.fSettings.fCaps->canUseFragCoord();
807 if (positionWorkaround) {
808 this->write("sk_FragCoord_Workaround = (");
809 }
ethannicholasf789b382016-08-03 12:43:36 -0700810 this->writeExpression(*b.fLeft, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700811 this->write(" ");
812 this->write(Compiler::OperatorName(b.fOperator));
813 this->write(" ");
ethannicholasf789b382016-08-03 12:43:36 -0700814 this->writeExpression(*b.fRight, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +0000815 if (positionWorkaround) {
816 this->write(")");
817 }
ethannicholasf789b382016-08-03 12:43:36 -0700818 if (precedence >= parentPrecedence) {
819 this->write(")");
820 }
821}
822
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400823void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -0700824 Precedence parentPrecedence) {
825 if (kTernary_Precedence >= parentPrecedence) {
826 this->write("(");
827 }
828 this->writeExpression(*t.fTest, kTernary_Precedence);
829 this->write(" ? ");
830 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
831 this->write(" : ");
832 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
833 if (kTernary_Precedence >= parentPrecedence) {
834 this->write(")");
835 }
836}
837
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400838void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700839 Precedence parentPrecedence) {
840 if (kPrefix_Precedence >= parentPrecedence) {
841 this->write("(");
842 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700843 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700844 this->writeExpression(*p.fOperand, kPrefix_Precedence);
845 if (kPrefix_Precedence >= parentPrecedence) {
846 this->write(")");
847 }
848}
849
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400850void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700851 Precedence parentPrecedence) {
852 if (kPostfix_Precedence >= parentPrecedence) {
853 this->write("(");
854 }
855 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700856 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -0700857 if (kPostfix_Precedence >= parentPrecedence) {
858 this->write(")");
859 }
860}
861
862void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
863 this->write(b.fValue ? "true" : "false");
864}
865
866void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholas5961bc92016-10-12 06:39:56 -0700867 if (i.fType == *fContext.fUInt_Type) {
868 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas58d56482017-12-19 09:29:22 -0500869 } else if (i.fType == *fContext.fUShort_Type) {
870 this->write(to_string(i.fValue & 0xffff) + "u");
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400871 } else if (i.fType == *fContext.fUByte_Type) {
872 this->write(to_string(i.fValue & 0xff) + "u");
873 } else {
ethannicholas5961bc92016-10-12 06:39:56 -0700874 this->write(to_string((int32_t) i.fValue));
875 }
ethannicholasf789b382016-08-03 12:43:36 -0700876}
877
878void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
879 this->write(to_string(f.fValue));
880}
881
Ethan Nicholas762466e2017-06-29 10:03:38 -0400882void GLSLCodeGenerator::writeSetting(const Setting& s) {
883 ABORT("internal error; setting was not folded to a constant during compilation\n");
884}
885
ethannicholasf789b382016-08-03 12:43:36 -0700886void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholas6c48e4d2018-07-19 20:10:37 +0000887 this->writeTypePrecision(f.fDeclaration.fReturnType);
888 this->writeType(f.fDeclaration.fReturnType);
889 this->write(" " + f.fDeclaration.fName + "(");
890 const char* separator = "";
891 for (const auto& param : f.fDeclaration.fParameters) {
892 this->write(separator);
893 separator = ", ";
894 this->writeModifiers(param->fModifiers, false);
895 std::vector<int> sizes;
896 const Type* type = &param->fType;
897 while (type->kind() == Type::kArray_Kind) {
898 sizes.push_back(type->columns());
899 type = &type->componentType();
900 }
901 this->writeTypePrecision(*type);
902 this->writeType(*type);
903 this->write(" " + param->fName);
904 for (int s : sizes) {
905 if (s <= 0) {
906 this->write("[]");
907 } else {
908 this->write("[" + to_string(s) + "]");
ethannicholas5961bc92016-10-12 06:39:56 -0700909 }
910 }
ethannicholasf789b382016-08-03 12:43:36 -0700911 }
Ethan Nicholas6c48e4d2018-07-19 20:10:37 +0000912 this->writeLine(") {");
913
ethannicholas5961bc92016-10-12 06:39:56 -0700914 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400915 OutputStream* oldOut = fOut;
916 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -0700917 fOut = &buffer;
Ethan Nicholas6c48e4d2018-07-19 20:10:37 +0000918 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -0400919 this->writeStatements(((Block&) *f.fBody).fStatements);
Ethan Nicholas6c48e4d2018-07-19 20:10:37 +0000920 fIndentation--;
921 this->writeLine("}");
ethannicholas5961bc92016-10-12 06:39:56 -0700922
923 fOut = oldOut;
924 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400925 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -0700926}
927
Greg Daniel64773e62016-11-22 09:44:03 -0500928void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -0700929 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -0500930 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
931 this->write("flat ");
932 }
ethannicholas5961bc92016-10-12 06:39:56 -0700933 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
934 this->write("noperspective ");
935 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400936 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -0500937 if (layout.size()) {
938 this->write(layout + " ");
939 }
Brian Salomonf9f45122016-11-29 11:59:17 -0500940 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
941 this->write("readonly ");
942 }
943 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
944 this->write("writeonly ");
945 }
946 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
947 this->write("coherent ");
948 }
949 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
950 this->write("volatile ");
951 }
952 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
953 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -0700954 }
Greg Daniel64773e62016-11-22 09:44:03 -0500955 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -0700956 (modifiers.fFlags & Modifiers::kOut_Flag)) {
957 this->write("inout ");
958 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500959 if (globalContext &&
960 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700961 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
962 : "varying ");
963 } else {
964 this->write("in ");
965 }
966 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500967 if (globalContext &&
968 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -0700969 this->write("varying ");
970 } else {
971 this->write("out ");
972 }
973 }
974 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
975 this->write("uniform ");
976 }
977 if (modifiers.fFlags & Modifiers::kConst_Flag) {
978 this->write("const ");
979 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400980 if (usesPrecisionModifiers()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700981 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
982 this->write("lowp ");
983 }
984 if (modifiers.fFlags & Modifiers::kMediump_Flag) {
985 this->write("mediump ");
986 }
987 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
988 this->write("highp ");
989 }
990 }
ethannicholasf789b382016-08-03 12:43:36 -0700991}
992
993void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -0500994 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -0700995 return;
996 }
ethannicholas5961bc92016-10-12 06:39:56 -0700997 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -0500998 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -0700999 fIndentation++;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001000 const Type* structType = &intf.fVariable.fType;
1001 while (structType->kind() == Type::kArray_Kind) {
1002 structType = &structType->componentType();
1003 }
1004 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001005 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001006 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001007 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001008 this->writeLine(" " + f.fName + ";");
1009 }
1010 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001011 this->write("}");
1012 if (intf.fInstanceName.size()) {
1013 this->write(" ");
1014 this->write(intf.fInstanceName);
1015 for (const auto& size : intf.fSizes) {
1016 this->write("[");
1017 if (size) {
1018 this->writeExpression(*size, kTopLevel_Precedence);
1019 }
1020 this->write("]");
1021 }
1022 }
1023 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001024}
1025
Ethan Nicholas762466e2017-06-29 10:03:38 -04001026void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1027 this->writeExpression(value, kTopLevel_Precedence);
1028}
1029
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001030const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1031 if (usesPrecisionModifiers()) {
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001032 switch (type.kind()) {
1033 case Type::kScalar_Kind:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001034 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1035 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001036 if (fProgram.fSettings.fForceHighPrecision ||
1037 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1038 return "highp ";
1039 }
1040 return "mediump ";
1041 }
1042 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001043 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001044 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001045 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1046 type == *fContext.fUInt_Type) {
1047 return "highp ";
1048 }
1049 return "";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001050 case Type::kVector_Kind: // fall through
1051 case Type::kMatrix_Kind:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001052 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001053 default:
1054 break;
1055 }
1056 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001057 return "";
1058}
1059
1060void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1061 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001062}
1063
ethannicholas5961bc92016-10-12 06:39:56 -07001064void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001065 if (!decl.fVars.size()) {
1066 return;
1067 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001068 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001069 for (const auto& stmt : decl.fVars) {
1070 VarDeclaration& var = (VarDeclaration&) *stmt;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001071 if (wroteType) {
1072 this->write(", ");
1073 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001074 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001075 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001076 this->writeType(decl.fBaseType);
1077 this->write(" ");
1078 wroteType = true;
1079 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001080 this->write(var.fVar->fName);
1081 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001082 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001083 if (size) {
1084 this->writeExpression(*size, kTopLevel_Precedence);
1085 }
ethannicholasf789b382016-08-03 12:43:36 -07001086 this->write("]");
1087 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001088 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001089 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001090 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001091 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001092 if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001093 if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001094 fHeader.writeText("#extension ");
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001095 fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001096 fHeader.writeText(" : require\n");
Brian Salomon2a51de82016-11-16 12:06:01 -05001097 }
1098 fFoundImageDecl = true;
1099 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001100 if (!fFoundExternalSamplerDecl && var.fVar->fType == *fContext.fSamplerExternalOES_Type) {
1101 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
1102 fHeader.writeText("#extension ");
1103 fHeader.writeText(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman6cd92682018-04-25 13:13:19 -04001104 fHeader.writeText(" : enable\n");
Brian Osman4b2f9152018-04-17 11:19:57 -04001105 }
Brian Osman061020e2018-04-17 14:22:15 -04001106 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
1107 fHeader.writeText("#extension ");
1108 fHeader.writeText(fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman6cd92682018-04-25 13:13:19 -04001109 fHeader.writeText(" : enable\n");
Brian Osman061020e2018-04-17 14:22:15 -04001110 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001111 fFoundExternalSamplerDecl = true;
1112 }
ethannicholasf789b382016-08-03 12:43:36 -07001113 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001114 if (wroteType) {
1115 this->write(";");
1116 }
ethannicholasf789b382016-08-03 12:43:36 -07001117}
1118
1119void GLSLCodeGenerator::writeStatement(const Statement& s) {
1120 switch (s.fKind) {
1121 case Statement::kBlock_Kind:
1122 this->writeBlock((Block&) s);
1123 break;
1124 case Statement::kExpression_Kind:
1125 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
1126 this->write(";");
1127 break;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001128 case Statement::kReturn_Kind:
ethannicholasf789b382016-08-03 12:43:36 -07001129 this->writeReturnStatement((ReturnStatement&) s);
1130 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07001131 case Statement::kVarDeclarations_Kind:
ethannicholas5961bc92016-10-12 06:39:56 -07001132 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001133 break;
1134 case Statement::kIf_Kind:
1135 this->writeIfStatement((IfStatement&) s);
1136 break;
1137 case Statement::kFor_Kind:
1138 this->writeForStatement((ForStatement&) s);
1139 break;
1140 case Statement::kWhile_Kind:
1141 this->writeWhileStatement((WhileStatement&) s);
1142 break;
1143 case Statement::kDo_Kind:
1144 this->writeDoStatement((DoStatement&) s);
1145 break;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001146 case Statement::kSwitch_Kind:
1147 this->writeSwitchStatement((SwitchStatement&) s);
1148 break;
ethannicholasf789b382016-08-03 12:43:36 -07001149 case Statement::kBreak_Kind:
1150 this->write("break;");
1151 break;
1152 case Statement::kContinue_Kind:
1153 this->write("continue;");
1154 break;
1155 case Statement::kDiscard_Kind:
1156 this->write("discard;");
1157 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001158 case Statement::kNop_Kind:
1159 this->write(";");
1160 break;
ethannicholasf789b382016-08-03 12:43:36 -07001161 default:
1162 ABORT("unsupported statement: %s", s.description().c_str());
1163 }
1164}
1165
Ethan Nicholascb670962017-04-20 19:31:52 -04001166void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1167 for (const auto& s : statements) {
1168 if (!s->isEmpty()) {
1169 this->writeStatement(*s);
1170 this->writeLine();
1171 }
1172 }
1173}
1174
ethannicholasf789b382016-08-03 12:43:36 -07001175void GLSLCodeGenerator::writeBlock(const Block& b) {
1176 this->writeLine("{");
1177 fIndentation++;
Ethan Nicholascb670962017-04-20 19:31:52 -04001178 this->writeStatements(b.fStatements);
ethannicholasf789b382016-08-03 12:43:36 -07001179 fIndentation--;
1180 this->write("}");
1181}
1182
1183void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1184 this->write("if (");
1185 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1186 this->write(") ");
1187 this->writeStatement(*stmt.fIfTrue);
1188 if (stmt.fIfFalse) {
1189 this->write(" else ");
1190 this->writeStatement(*stmt.fIfFalse);
1191 }
1192}
1193
1194void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1195 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001196 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001197 this->writeStatement(*f.fInitializer);
1198 } else {
1199 this->write("; ");
1200 }
1201 if (f.fTest) {
1202 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1203 }
1204 this->write("; ");
1205 if (f.fNext) {
1206 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1207 }
1208 this->write(") ");
1209 this->writeStatement(*f.fStatement);
1210}
1211
1212void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1213 this->write("while (");
1214 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1215 this->write(") ");
1216 this->writeStatement(*w.fStatement);
1217}
1218
1219void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1220 this->write("do ");
1221 this->writeStatement(*d.fStatement);
1222 this->write(" while (");
1223 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1224 this->write(");");
1225}
1226
Ethan Nicholasaf197692017-02-27 13:26:45 -05001227void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1228 this->write("switch (");
1229 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1230 this->writeLine(") {");
1231 fIndentation++;
1232 for (const auto& c : s.fCases) {
1233 if (c->fValue) {
1234 this->write("case ");
1235 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1236 this->writeLine(":");
1237 } else {
1238 this->writeLine("default:");
1239 }
1240 fIndentation++;
1241 for (const auto& stmt : c->fStatements) {
1242 this->writeStatement(*stmt);
1243 this->writeLine();
1244 }
1245 fIndentation--;
1246 }
1247 fIndentation--;
1248 this->write("}");
1249}
1250
ethannicholasf789b382016-08-03 12:43:36 -07001251void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1252 this->write("return");
1253 if (r.fExpression) {
1254 this->write(" ");
1255 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1256 }
1257 this->write(";");
1258}
1259
Ethan Nicholas762466e2017-06-29 10:03:38 -04001260void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001261 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001262 this->writeLine();
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001263 for (const auto& e : fProgram) {
1264 if (e.fKind == ProgramElement::kExtension_Kind) {
1265 this->writeExtension((Extension&) e);
ethannicholas5961bc92016-10-12 06:39:56 -07001266 }
1267 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001268}
1269
Ethan Nicholas762466e2017-06-29 10:03:38 -04001270void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1271 switch (e.fKind) {
1272 case ProgramElement::kExtension_Kind:
1273 break;
1274 case ProgramElement::kVar_Kind: {
1275 VarDeclarations& decl = (VarDeclarations&) e;
1276 if (decl.fVars.size() > 0) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001277 int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001278 if (builtin == -1) {
1279 // normal var
1280 this->writeVarDeclarations(decl, true);
1281 this->writeLine();
1282 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1283 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
Brian Salomondc092132018-04-04 10:14:16 -04001284 if (fProgram.fSettings.fFragColorIsInOut) {
1285 this->write("inout ");
1286 } else {
1287 this->write("out ");
1288 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001289 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001290 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001291 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001292 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001293 }
Mike Klein5ce39722017-06-27 22:52:03 +00001294 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001295 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001296 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001297 case ProgramElement::kInterfaceBlock_Kind:
1298 this->writeInterfaceBlock((InterfaceBlock&) e);
1299 break;
1300 case ProgramElement::kFunction_Kind:
1301 this->writeFunction((FunctionDefinition&) e);
1302 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001303 case ProgramElement::kModifiers_Kind: {
1304 const Modifiers& modifiers = ((ModifiersDeclaration&) e).fModifiers;
1305 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1306 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
1307 fHeader.writeText("#extension ");
1308 fHeader.writeText(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
1309 fHeader.writeText(" : require\n");
1310 }
1311 fFoundGSInvocations = true;
1312 }
1313 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001314 this->writeLine(";");
1315 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001316 }
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001317 case ProgramElement::kEnum_Kind:
1318 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001319 default:
1320 printf("%s\n", e.description().c_str());
1321 ABORT("unsupported program element");
Ethan Nicholasc0709392017-06-27 11:20:22 -04001322 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001323}
1324
1325bool GLSLCodeGenerator::generateCode() {
1326 OutputStream* rawOut = fOut;
1327 fOut = &fHeader;
1328 fProgramKind = fProgram.fKind;
Ethan Nicholas6c48e4d2018-07-19 20:10:37 +00001329 this->writeHeader();
Chris Dalton8fd79552018-01-11 00:46:14 -05001330 if (Program::kGeometry_Kind == fProgramKind &&
1331 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
1332 fHeader.writeText("#extension ");
1333 fHeader.writeText(fProgram.fSettings.fCaps->geometryShaderExtensionString());
1334 fHeader.writeText(" : require\n");
1335 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001336 StringStream body;
1337 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001338 for (const auto& e : fProgram) {
1339 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001340 }
1341 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001342
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001343 write_stringstream(fHeader, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001344
1345 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1346 Layout layout;
1347 switch (fProgram.fKind) {
1348 case Program::kVertex_Kind: {
1349 Modifiers modifiers(layout, Modifiers::kOut_Flag | Modifiers::kHighp_Flag);
1350 this->writeModifiers(modifiers, true);
1351 this->write("vec4 sk_FragCoord_Workaround;\n");
1352 break;
1353 }
1354 case Program::kFragment_Kind: {
1355 Modifiers modifiers(layout, Modifiers::kIn_Flag | Modifiers::kHighp_Flag);
1356 this->writeModifiers(modifiers, true);
1357 this->write("vec4 sk_FragCoord_Workaround;\n");
1358 break;
1359 }
1360 default:
1361 break;
1362 }
1363 }
1364
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001365 if (this->usesPrecisionModifiers()) {
1366 this->writeLine("precision mediump float;");
1367 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001368 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001369 write_stringstream(body, *rawOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001370 return true;
ethannicholasf789b382016-08-03 12:43:36 -07001371}
1372
1373}