1 /*
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 */
7
8 #include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
9
10 #include <memory>
11
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/ir/SkSLExpressionStatement.h"
14 #include "src/sksl/ir/SkSLExtension.h"
15 #include "src/sksl/ir/SkSLIndexExpression.h"
16 #include "src/sksl/ir/SkSLModifiersDeclaration.h"
17 #include "src/sksl/ir/SkSLNop.h"
18 #include "src/sksl/ir/SkSLStructDefinition.h"
19 #include "src/sksl/ir/SkSLVariableReference.h"
20
21 #ifndef SKSL_STANDALONE
22 #include "include/private/SkOnce.h"
23 #endif
24
25 namespace SkSL {
26
write(const char * s)27 void GLSLCodeGenerator::write(const char* s) {
28 if (s[0] == 0) {
29 return;
30 }
31 if (fAtLineStart) {
32 for (int i = 0; i < fIndentation; i++) {
33 fOut->writeText(" ");
34 }
35 }
36 fOut->writeText(s);
37 fAtLineStart = false;
38 }
39
writeLine(const char * s)40 void GLSLCodeGenerator::writeLine(const char* s) {
41 this->write(s);
42 this->writeLine();
43 }
44
write(const String & s)45 void GLSLCodeGenerator::write(const String& s) {
46 this->write(s.c_str());
47 }
48
write(StringFragment s)49 void GLSLCodeGenerator::write(StringFragment s) {
50 if (!s.fLength) {
51 return;
52 }
53 if (fAtLineStart) {
54 for (int i = 0; i < fIndentation; i++) {
55 fOut->writeText(" ");
56 }
57 }
58 fOut->write(s.fChars, s.fLength);
59 fAtLineStart = false;
60 }
61
writeLine(const String & s)62 void GLSLCodeGenerator::writeLine(const String& s) {
63 this->writeLine(s.c_str());
64 }
65
writeLine()66 void GLSLCodeGenerator::writeLine() {
67 fOut->writeText(fLineEnding);
68 fAtLineStart = true;
69 }
70
finishLine()71 void GLSLCodeGenerator::finishLine() {
72 if (!fAtLineStart) {
73 this->writeLine();
74 }
75 }
76
writeExtension(const String & name)77 void GLSLCodeGenerator::writeExtension(const String& name) {
78 this->writeExtension(name, true);
79 }
80
writeExtension(const String & name,bool require)81 void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
82 fExtensions.writeText("#extension ");
83 fExtensions.write(name.c_str(), name.length());
84 fExtensions.writeText(require ? " : require\n" : " : enable\n");
85 }
86
usesPrecisionModifiers() const87 bool GLSLCodeGenerator::usesPrecisionModifiers() const {
88 return this->caps().usesPrecisionModifiers();
89 }
90
91 // Returns the name of the type with array dimensions, e.g. `float[2]`.
getTypeName(const Type & type)92 String GLSLCodeGenerator::getTypeName(const Type& type) {
93 switch (type.typeKind()) {
94 case Type::TypeKind::kVector: {
95 const Type& component = type.componentType();
96 String result;
97 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
98 result = "vec";
99 }
100 else if (component.isSigned()) {
101 result = "ivec";
102 }
103 else if (component.isUnsigned()) {
104 result = "uvec";
105 }
106 else if (component == *fContext.fTypes.fBool) {
107 result = "bvec";
108 }
109 else {
110 SK_ABORT("unsupported vector type");
111 }
112 result += to_string(type.columns());
113 return result;
114 }
115 case Type::TypeKind::kMatrix: {
116 String result;
117 const Type& component = type.componentType();
118 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
119 result = "mat";
120 }
121 else {
122 SK_ABORT("unsupported matrix type");
123 }
124 result += to_string(type.columns());
125 if (type.columns() != type.rows()) {
126 result += "x";
127 result += to_string(type.rows());
128 }
129 return result;
130 }
131 case Type::TypeKind::kArray: {
132 String baseTypeName = this->getTypeName(type.componentType());
133 return (type.columns() == Type::kUnsizedArray)
134 ? String::printf("%s[]", baseTypeName.c_str())
135 : String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
136 }
137 case Type::TypeKind::kScalar: {
138 if (type == *fContext.fTypes.fHalf) {
139 return "float";
140 }
141 else if (type == *fContext.fTypes.fShort) {
142 return "int";
143 }
144 else if (type == *fContext.fTypes.fUShort) {
145 return "uint";
146 }
147 else {
148 return type.name();
149 }
150 break;
151 }
152 case Type::TypeKind::kEnum:
153 return "int";
154 default:
155 return type.name();
156 }
157 }
158
writeStructDefinition(const StructDefinition & s)159 void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) {
160 const Type& type = s.type();
161 this->write("struct ");
162 this->write(type.name());
163 this->writeLine(" {");
164 fIndentation++;
165 for (const auto& f : type.fields()) {
166 this->writeModifiers(f.fModifiers, false);
167 this->writeTypePrecision(*f.fType);
168 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
169 this->writeType(baseType);
170 this->write(" ");
171 this->write(f.fName);
172 if (f.fType->isArray()) {
173 this->write("[" + to_string(f.fType->columns()) + "]");
174 }
175 this->writeLine(";");
176 }
177 fIndentation--;
178 this->writeLine("};");
179 }
180
writeType(const Type & type)181 void GLSLCodeGenerator::writeType(const Type& type) {
182 this->write(this->getTypeName(type));
183 }
184
writeExpression(const Expression & expr,Precedence parentPrecedence)185 void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
186 switch (expr.kind()) {
187 case Expression::Kind::kBinary:
188 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
189 break;
190 case Expression::Kind::kBoolLiteral:
191 this->writeBoolLiteral(expr.as<BoolLiteral>());
192 break;
193 case Expression::Kind::kConstructorArray:
194 case Expression::Kind::kConstructorCompound:
195 case Expression::Kind::kConstructorDiagonalMatrix:
196 case Expression::Kind::kConstructorMatrixResize:
197 case Expression::Kind::kConstructorSplat:
198 case Expression::Kind::kConstructorStruct:
199 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
200 break;
201 case Expression::Kind::kConstructorScalarCast:
202 case Expression::Kind::kConstructorCompoundCast:
203 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
204 break;
205 case Expression::Kind::kIntLiteral:
206 this->writeIntLiteral(expr.as<IntLiteral>());
207 break;
208 case Expression::Kind::kFieldAccess:
209 this->writeFieldAccess(expr.as<FieldAccess>());
210 break;
211 case Expression::Kind::kFloatLiteral:
212 this->writeFloatLiteral(expr.as<FloatLiteral>());
213 break;
214 case Expression::Kind::kFunctionCall:
215 this->writeFunctionCall(expr.as<FunctionCall>());
216 break;
217 case Expression::Kind::kPrefix:
218 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
219 break;
220 case Expression::Kind::kPostfix:
221 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
222 break;
223 case Expression::Kind::kSetting:
224 this->writeSetting(expr.as<Setting>());
225 break;
226 case Expression::Kind::kSwizzle:
227 this->writeSwizzle(expr.as<Swizzle>());
228 break;
229 case Expression::Kind::kVariableReference:
230 this->writeVariableReference(expr.as<VariableReference>());
231 break;
232 case Expression::Kind::kTernary:
233 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
234 break;
235 case Expression::Kind::kIndex:
236 this->writeIndexExpression(expr.as<IndexExpression>());
237 break;
238 default:
239 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
240 break;
241 }
242 }
243
is_abs(Expression & expr)244 static bool is_abs(Expression& expr) {
245 if (expr.kind() != Expression::Kind::kFunctionCall) {
246 return false;
247 }
248 return expr.as<FunctionCall>().function().name() == "abs";
249 }
250
251 // turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
252 // Tegra3 compiler bug.
writeMinAbsHack(Expression & absExpr,Expression & otherExpr)253 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
254 SkASSERT(!this->caps().canUseMinAndAbsTogether());
255 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
256 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
257 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.type()) +
258 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
259 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.type()) +
260 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
261 this->write("((" + tmpVar1 + " = ");
262 this->writeExpression(absExpr, Precedence::kTopLevel);
263 this->write(") < (" + tmpVar2 + " = ");
264 this->writeExpression(otherExpr, Precedence::kAssignment);
265 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
266 }
267
writeInverseSqrtHack(const Expression & x)268 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
269 this->write("(1.0 / sqrt(");
270 this->writeExpression(x, Precedence::kTopLevel);
271 this->write("))");
272 }
273
writeDeterminantHack(const Expression & mat)274 void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
275 String name;
276 const Type& type = mat.type();
277 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
278 name = "_determinant2";
279 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
280 fWrittenIntrinsics.insert(name);
281 fExtraFunctions.writeText((
282 "float " + name + "(mat2 m) {"
283 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
284 "}"
285 ).c_str());
286 }
287 }
288 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
289 name = "_determinant3";
290 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
291 fWrittenIntrinsics.insert(name);
292 fExtraFunctions.writeText((
293 "float " + name + "(mat3 m) {"
294 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
295 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
296 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
297 " float b01 = a22 * a11 - a12 * a21;"
298 " float b11 = -a22 * a10 + a12 * a20;"
299 " float b21 = a21 * a10 - a11 * a20;"
300 " return a00 * b01 + a01 * b11 + a02 * b21;"
301 "}"
302 ).c_str());
303 }
304 }
305 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
306 name = "_determinant4";
307 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
308 fWrittenIntrinsics.insert(name);
309 fExtraFunctions.writeText((
310 "mat4 " + name + "(mat4 m) {"
311 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
312 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
313 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
314 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
315 " float b00 = a00 * a11 - a01 * a10;"
316 " float b01 = a00 * a12 - a02 * a10;"
317 " float b02 = a00 * a13 - a03 * a10;"
318 " float b03 = a01 * a12 - a02 * a11;"
319 " float b04 = a01 * a13 - a03 * a11;"
320 " float b05 = a02 * a13 - a03 * a12;"
321 " float b06 = a20 * a31 - a21 * a30;"
322 " float b07 = a20 * a32 - a22 * a30;"
323 " float b08 = a20 * a33 - a23 * a30;"
324 " float b09 = a21 * a32 - a22 * a31;"
325 " float b10 = a21 * a33 - a23 * a31;"
326 " float b11 = a22 * a33 - a23 * a32;"
327 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
328 "}"
329 ).c_str());
330 }
331 }
332 else {
333 SkASSERT(false);
334 }
335 this->write(name + "(");
336 this->writeExpression(mat, Precedence::kTopLevel);
337 this->write(")");
338 }
339
writeInverseHack(const Expression & mat)340 void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
341 String name;
342 const Type& type = mat.type();
343 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
344 name = "_inverse2";
345 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
346 fWrittenIntrinsics.insert(name);
347 fExtraFunctions.writeText((
348 "mat2 " + name + "(mat2 m) {"
349 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
350 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
351 "}"
352 ).c_str());
353 }
354 }
355 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
356 name = "_inverse3";
357 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
358 fWrittenIntrinsics.insert(name);
359 fExtraFunctions.writeText((
360 "mat3 " + name + "(mat3 m) {"
361 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
362 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
363 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
364 " float b01 = a22 * a11 - a12 * a21;"
365 " float b11 = -a22 * a10 + a12 * a20;"
366 " float b21 = a21 * a10 - a11 * a20;"
367 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
368 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
369 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
370 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
371 "}"
372 ).c_str());
373 }
374 }
375 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
376 name = "_inverse4";
377 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
378 fWrittenIntrinsics.insert(name);
379 fExtraFunctions.writeText((
380 "mat4 " + name + "(mat4 m) {"
381 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
382 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
383 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
384 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
385 " float b00 = a00 * a11 - a01 * a10;"
386 " float b01 = a00 * a12 - a02 * a10;"
387 " float b02 = a00 * a13 - a03 * a10;"
388 " float b03 = a01 * a12 - a02 * a11;"
389 " float b04 = a01 * a13 - a03 * a11;"
390 " float b05 = a02 * a13 - a03 * a12;"
391 " float b06 = a20 * a31 - a21 * a30;"
392 " float b07 = a20 * a32 - a22 * a30;"
393 " float b08 = a20 * a33 - a23 * a30;"
394 " float b09 = a21 * a32 - a22 * a31;"
395 " float b10 = a21 * a33 - a23 * a31;"
396 " float b11 = a22 * a33 - a23 * a32;"
397 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
398 " b04 * b07 + b05 * b06;"
399 " return mat4("
400 " a11 * b11 - a12 * b10 + a13 * b09,"
401 " a02 * b10 - a01 * b11 - a03 * b09,"
402 " a31 * b05 - a32 * b04 + a33 * b03,"
403 " a22 * b04 - a21 * b05 - a23 * b03,"
404 " a12 * b08 - a10 * b11 - a13 * b07,"
405 " a00 * b11 - a02 * b08 + a03 * b07,"
406 " a32 * b02 - a30 * b05 - a33 * b01,"
407 " a20 * b05 - a22 * b02 + a23 * b01,"
408 " a10 * b10 - a11 * b08 + a13 * b06,"
409 " a01 * b08 - a00 * b10 - a03 * b06,"
410 " a30 * b04 - a31 * b02 + a33 * b00,"
411 " a21 * b02 - a20 * b04 - a23 * b00,"
412 " a11 * b07 - a10 * b09 - a12 * b06,"
413 " a00 * b09 - a01 * b07 + a02 * b06,"
414 " a31 * b01 - a30 * b03 - a32 * b00,"
415 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
416 "}"
417 ).c_str());
418 }
419 }
420 else {
421 SkASSERT(false);
422 }
423 this->write(name + "(");
424 this->writeExpression(mat, Precedence::kTopLevel);
425 this->write(")");
426 }
427
writeTransposeHack(const Expression & mat)428 void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
429 const Type& type = mat.type();
430 String name = "transpose" + to_string(type.columns()) + to_string(type.rows());
431 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
432 fWrittenIntrinsics.insert(name);
433 String typeName = this->getTypeName(type);
434 const Type& base = type.componentType();
435 String transposed = this->getTypeName(base.toCompound(fContext,
436 type.rows(),
437 type.columns()));
438 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " +
439 transposed + "(").c_str());
440 const char* separator = "";
441 for (int row = 0; row < type.rows(); ++row) {
442 for (int column = 0; column < type.columns(); ++column) {
443 fExtraFunctions.writeText(separator);
444 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
445 "]").c_str());
446 separator = ", ";
447 }
448 }
449 fExtraFunctions.writeText("); }");
450 }
451 this->write(name + "(");
452 this->writeExpression(mat, Precedence::kTopLevel);
453 this->write(")");
454 }
455
writeFunctionCall(const FunctionCall & c)456 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
457 const FunctionDeclaration& function = c.function();
458 const ExpressionArray& arguments = c.arguments();
459 bool isTextureFunctionWithBias = false;
460 bool nameWritten = false;
461 switch (c.function().intrinsicKind()) {
462 case k_abs_IntrinsicKind: {
463 if (!this->caps().emulateAbsIntFunction())
464 break;
465 SkASSERT(arguments.size() == 1);
466 if (arguments[0]->type() != *fContext.fTypes.fInt) {
467 break;
468 }
469 // abs(int) on Intel OSX is incorrect, so emulate it:
470 String name = "_absemulation";
471 this->write(name);
472 nameWritten = true;
473 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
474 fWrittenIntrinsics.insert(name);
475 fExtraFunctions.writeText((
476 "int " + name + "(int x) {\n"
477 " return x * sign(x);\n"
478 "}\n"
479 ).c_str());
480 }
481 break;
482 }
483 case k_atan_IntrinsicKind:
484 if (this->caps().mustForceNegatedAtanParamToFloat() &&
485 arguments.size() == 2 &&
486 arguments[1]->kind() == Expression::Kind::kPrefix) {
487 const PrefixExpression& p = (PrefixExpression&) *arguments[1];
488 if (p.getOperator().kind() == Token::Kind::TK_MINUS) {
489 this->write("atan(");
490 this->writeExpression(*arguments[0], Precedence::kSequence);
491 this->write(", -1.0 * ");
492 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
493 this->write(")");
494 return;
495 }
496 }
497 break;
498 case k_dFdy_IntrinsicKind:
499 if (fProgram.fConfig->fSettings.fFlipY) {
500 // Flipping Y also negates the Y derivatives.
501 this->write("-dFdy");
502 nameWritten = true;
503 }
504 [[fallthrough]];
505 case k_dFdx_IntrinsicKind:
506 case k_fwidth_IntrinsicKind:
507 if (!fFoundDerivatives &&
508 this->caps().shaderDerivativeExtensionString()) {
509 this->writeExtension(this->caps().shaderDerivativeExtensionString());
510 fFoundDerivatives = true;
511 }
512 break;
513 case k_determinant_IntrinsicKind:
514 if (!this->caps().builtinDeterminantSupport()) {
515 SkASSERT(arguments.size() == 1);
516 this->writeDeterminantHack(*arguments[0]);
517 return;
518 }
519 break;
520 case k_fma_IntrinsicKind:
521 if (!this->caps().builtinFMASupport()) {
522 SkASSERT(arguments.size() == 3);
523 this->write("((");
524 this->writeExpression(*arguments[0], Precedence::kSequence);
525 this->write(") * (");
526 this->writeExpression(*arguments[1], Precedence::kSequence);
527 this->write(") + (");
528 this->writeExpression(*arguments[2], Precedence::kSequence);
529 this->write("))");
530 return;
531 }
532 break;
533 case k_fract_IntrinsicKind:
534 if (!this->caps().canUseFractForNegativeValues()) {
535 SkASSERT(arguments.size() == 1);
536 this->write("(0.5 - sign(");
537 this->writeExpression(*arguments[0], Precedence::kSequence);
538 this->write(") * (0.5 - fract(abs(");
539 this->writeExpression(*arguments[0], Precedence::kSequence);
540 this->write("))))");
541 return;
542 }
543 break;
544 case k_inverse_IntrinsicKind:
545 if (this->caps().generation() < k140_GrGLSLGeneration) {
546 SkASSERT(arguments.size() == 1);
547 this->writeInverseHack(*arguments[0]);
548 return;
549 }
550 break;
551 case k_inversesqrt_IntrinsicKind:
552 if (this->caps().generation() < k130_GrGLSLGeneration) {
553 SkASSERT(arguments.size() == 1);
554 this->writeInverseSqrtHack(*arguments[0]);
555 return;
556 }
557 break;
558 case k_min_IntrinsicKind:
559 if (!this->caps().canUseMinAndAbsTogether()) {
560 SkASSERT(arguments.size() == 2);
561 if (is_abs(*arguments[0])) {
562 this->writeMinAbsHack(*arguments[0], *arguments[1]);
563 return;
564 }
565 if (is_abs(*arguments[1])) {
566 // note that this violates the GLSL left-to-right evaluation semantics.
567 // I doubt it will ever end up mattering, but it's worth calling out.
568 this->writeMinAbsHack(*arguments[1], *arguments[0]);
569 return;
570 }
571 }
572 break;
573 case k_pow_IntrinsicKind:
574 if (!this->caps().removePowWithConstantExponent()) {
575 break;
576 }
577 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
578 // constant. It's hard to tell what constitutes "constant" here
579 // so just replace in all cases.
580
581 // Change pow(x, y) into exp2(y * log2(x))
582 this->write("exp2(");
583 this->writeExpression(*arguments[1], Precedence::kMultiplicative);
584 this->write(" * log2(");
585 this->writeExpression(*arguments[0], Precedence::kSequence);
586 this->write("))");
587 return;
588 case k_saturate_IntrinsicKind:
589 SkASSERT(arguments.size() == 1);
590 this->write("clamp(");
591 this->writeExpression(*arguments[0], Precedence::kSequence);
592 this->write(", 0.0, 1.0)");
593 return;
594 case k_sample_IntrinsicKind: {
595 const char* dim = "";
596 bool proj = false;
597 const Type& arg0Type = arguments[0]->type();
598 const Type& arg1Type = arguments[1]->type();
599 switch (arg0Type.dimensions()) {
600 case SpvDim1D:
601 dim = "1D";
602 isTextureFunctionWithBias = true;
603 if (arg1Type == *fContext.fTypes.fFloat) {
604 proj = false;
605 } else {
606 SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
607 proj = true;
608 }
609 break;
610 case SpvDim2D:
611 dim = "2D";
612 if (arg0Type != *fContext.fTypes.fSamplerExternalOES) {
613 isTextureFunctionWithBias = true;
614 }
615 if (arg1Type == *fContext.fTypes.fFloat2) {
616 proj = false;
617 } else {
618 SkASSERT(arg1Type == *fContext.fTypes.fFloat3);
619 proj = true;
620 }
621 break;
622 case SpvDim3D:
623 dim = "3D";
624 isTextureFunctionWithBias = true;
625 if (arg1Type == *fContext.fTypes.fFloat3) {
626 proj = false;
627 } else {
628 SkASSERT(arg1Type == *fContext.fTypes.fFloat4);
629 proj = true;
630 }
631 break;
632 case SpvDimCube:
633 dim = "Cube";
634 isTextureFunctionWithBias = true;
635 proj = false;
636 break;
637 case SpvDimRect:
638 dim = "2DRect";
639 proj = false;
640 break;
641 case SpvDimBuffer:
642 SkASSERT(false); // doesn't exist
643 dim = "Buffer";
644 proj = false;
645 break;
646 case SpvDimSubpassData:
647 SkASSERT(false); // doesn't exist
648 dim = "SubpassData";
649 proj = false;
650 break;
651 }
652 if (!fTextureFunctionOverride.empty()) {
653 this->write(fTextureFunctionOverride.c_str());
654 } else {
655 this->write("texture");
656 if (this->caps().generation() < k130_GrGLSLGeneration) {
657 this->write(dim);
658 }
659 if (proj) {
660 this->write("Proj");
661 }
662 }
663 nameWritten = true;
664 break;
665 }
666 case k_transpose_IntrinsicKind:
667 if (this->caps().generation() < k130_GrGLSLGeneration) {
668 SkASSERT(arguments.size() == 1);
669 this->writeTransposeHack(*arguments[0]);
670 return;
671 }
672 break;
673 default:
674 break;
675 }
676
677 if (!nameWritten) {
678 this->write(function.mangledName());
679 }
680 this->write("(");
681 const char* separator = "";
682 for (const auto& arg : arguments) {
683 this->write(separator);
684 separator = ", ";
685 this->writeExpression(*arg, Precedence::kSequence);
686 }
687 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
688 this->write(", -0.5");
689 }
690 this->write(")");
691 }
692
writeCastConstructor(const AnyConstructor & c,Precedence parentPrecedence)693 void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
694 const auto arguments = c.argumentSpan();
695 SkASSERT(arguments.size() == 1);
696
697 const Expression& argument = *arguments.front();
698 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
699 (argument.type() == *fContext.fTypes.fFloatLiteral))) {
700 // In cases like half(float), they're different types as far as SkSL is concerned but
701 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
702 // writing out the inner expression here.
703 this->writeExpression(argument, parentPrecedence);
704 return;
705 }
706
707 // This cast should be emitted as-is.
708 return this->writeAnyConstructor(c, parentPrecedence);
709 }
710
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)711 void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
712 this->writeType(c.type());
713 this->write("(");
714 const char* separator = "";
715 for (const auto& arg : c.argumentSpan()) {
716 this->write(separator);
717 separator = ", ";
718 this->writeExpression(*arg, Precedence::kSequence);
719 }
720 this->write(")");
721 }
722
writeFragCoord()723 void GLSLCodeGenerator::writeFragCoord() {
724 if (!this->caps().canUseFragCoord()) {
725 if (!fSetupFragCoordWorkaround) {
726 const char* precision = usesPrecisionModifiers() ? "highp " : "";
727 fFunctionHeader += precision;
728 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
729 fFunctionHeader += precision;
730 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
731 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
732 // Ensure that we get exact .5 values for x and y.
733 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
734 "vec2(.5);\n";
735 fSetupFragCoordWorkaround = true;
736 }
737 this->write("sk_FragCoord_Resolved");
738 return;
739 }
740
741 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
742 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
743 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
744 if (!fProgram.fConfig->fSettings.fFlipY) {
745 this->write("gl_FragCoord");
746 } else if (const char* extension = this->caps().fragCoordConventionsExtensionString()) {
747 if (!fSetupFragPositionGlobal) {
748 if (this->caps().generation() < k150_GrGLSLGeneration) {
749 this->writeExtension(extension);
750 }
751 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
752 fSetupFragPositionGlobal = true;
753 }
754 this->write("gl_FragCoord");
755 } else {
756 if (!fSetupFragPositionLocal) {
757 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
758 fFunctionHeader += " vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
759 " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
760 fSetupFragPositionLocal = true;
761 }
762 this->write("sk_FragCoord");
763 }
764 }
765
writeVariableReference(const VariableReference & ref)766 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
767 switch (ref.variable()->modifiers().fLayout.fBuiltin) {
768 case SK_FRAGCOLOR_BUILTIN:
769 if (this->caps().mustDeclareFragmentShaderOutput()) {
770 this->write("sk_FragColor");
771 } else {
772 this->write("gl_FragColor");
773 }
774 break;
775 case SK_FRAGCOORD_BUILTIN:
776 this->writeFragCoord();
777 break;
778 case SK_CLOCKWISE_BUILTIN:
779 this->write(fProgram.fConfig->fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
780 break;
781 case SK_VERTEXID_BUILTIN:
782 this->write("gl_VertexID");
783 break;
784 case SK_INSTANCEID_BUILTIN:
785 this->write("gl_InstanceID");
786 break;
787 case SK_IN_BUILTIN:
788 this->write("gl_in");
789 break;
790 case SK_INVOCATIONID_BUILTIN:
791 this->write("gl_InvocationID");
792 break;
793 case SK_LASTFRAGCOLOR_BUILTIN:
794 this->write(this->caps().fbFetchColorName());
795 break;
796 default:
797 this->write(ref.variable()->name());
798 }
799 }
800
writeIndexExpression(const IndexExpression & expr)801 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
802 this->writeExpression(*expr.base(), Precedence::kPostfix);
803 this->write("[");
804 this->writeExpression(*expr.index(), Precedence::kTopLevel);
805 this->write("]");
806 }
807
is_sk_position(const FieldAccess & f)808 bool is_sk_position(const FieldAccess& f) {
809 return "sk_Position" == f.base()->type().fields()[f.fieldIndex()].fName;
810 }
811
writeFieldAccess(const FieldAccess & f)812 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
813 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
814 this->writeExpression(*f.base(), Precedence::kPostfix);
815 this->write(".");
816 }
817 const Type& baseType = f.base()->type();
818 StringFragment name = baseType.fields()[f.fieldIndex()].fName;
819 if (name == "sk_Position") {
820 this->write("gl_Position");
821 } else if (name == "sk_PointSize") {
822 this->write("gl_PointSize");
823 } else {
824 this->write(baseType.fields()[f.fieldIndex()].fName);
825 }
826 }
827
writeSwizzle(const Swizzle & swizzle)828 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
829 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
830 this->write(".");
831 for (int c : swizzle.components()) {
832 SkASSERT(c >= 0 && c <= 3);
833 this->write(&("x\0y\0z\0w\0"[c * 2]));
834 }
835 }
836
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)837 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
838 Precedence parentPrecedence) {
839 const Expression& left = *b.left();
840 const Expression& right = *b.right();
841 Operator op = b.getOperator();
842 if (this->caps().unfoldShortCircuitAsTernary() &&
843 (op.kind() == Token::Kind::TK_LOGICALAND || op.kind() == Token::Kind::TK_LOGICALOR)) {
844 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
845 return;
846 }
847
848 Precedence precedence = op.getBinaryPrecedence();
849 if (precedence >= parentPrecedence) {
850 this->write("(");
851 }
852 bool positionWorkaround = fProgram.fConfig->fKind == ProgramKind::kVertex &&
853 op.isAssignment() &&
854 left.is<FieldAccess>() &&
855 is_sk_position(left.as<FieldAccess>()) &&
856 !right.containsRTAdjust() &&
857 !this->caps().canUseFragCoord();
858 if (positionWorkaround) {
859 this->write("sk_FragCoord_Workaround = (");
860 }
861 this->writeExpression(left, precedence);
862 this->write(" ");
863 this->write(op.operatorName());
864 this->write(" ");
865 this->writeExpression(right, precedence);
866 if (positionWorkaround) {
867 this->write(")");
868 }
869 if (precedence >= parentPrecedence) {
870 this->write(")");
871 }
872 }
873
writeShortCircuitWorkaroundExpression(const BinaryExpression & b,Precedence parentPrecedence)874 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
875 Precedence parentPrecedence) {
876 if (Precedence::kTernary >= parentPrecedence) {
877 this->write("(");
878 }
879
880 // Transform:
881 // a && b => a ? b : false
882 // a || b => a ? true : b
883 this->writeExpression(*b.left(), Precedence::kTernary);
884 this->write(" ? ");
885 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
886 this->writeExpression(*b.right(), Precedence::kTernary);
887 } else {
888 BoolLiteral boolTrue(/*offset=*/-1, /*value=*/true, fContext.fTypes.fBool.get());
889 this->writeBoolLiteral(boolTrue);
890 }
891 this->write(" : ");
892 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
893 BoolLiteral boolFalse(/*offset=*/-1, /*value=*/false, fContext.fTypes.fBool.get());
894 this->writeBoolLiteral(boolFalse);
895 } else {
896 this->writeExpression(*b.right(), Precedence::kTernary);
897 }
898 if (Precedence::kTernary >= parentPrecedence) {
899 this->write(")");
900 }
901 }
902
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)903 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
904 Precedence parentPrecedence) {
905 if (Precedence::kTernary >= parentPrecedence) {
906 this->write("(");
907 }
908 this->writeExpression(*t.test(), Precedence::kTernary);
909 this->write(" ? ");
910 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
911 this->write(" : ");
912 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
913 if (Precedence::kTernary >= parentPrecedence) {
914 this->write(")");
915 }
916 }
917
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)918 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
919 Precedence parentPrecedence) {
920 if (Precedence::kPrefix >= parentPrecedence) {
921 this->write("(");
922 }
923 this->write(p.getOperator().operatorName());
924 this->writeExpression(*p.operand(), Precedence::kPrefix);
925 if (Precedence::kPrefix >= parentPrecedence) {
926 this->write(")");
927 }
928 }
929
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)930 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
931 Precedence parentPrecedence) {
932 if (Precedence::kPostfix >= parentPrecedence) {
933 this->write("(");
934 }
935 this->writeExpression(*p.operand(), Precedence::kPostfix);
936 this->write(p.getOperator().operatorName());
937 if (Precedence::kPostfix >= parentPrecedence) {
938 this->write(")");
939 }
940 }
941
writeBoolLiteral(const BoolLiteral & b)942 void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
943 this->write(b.value() ? "true" : "false");
944 }
945
writeIntLiteral(const IntLiteral & i)946 void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
947 const Type& type = i.type();
948 if (type == *fContext.fTypes.fUInt) {
949 this->write(to_string(i.value() & 0xffffffff) + "u");
950 } else if (type == *fContext.fTypes.fUShort) {
951 this->write(to_string(i.value() & 0xffff) + "u");
952 } else {
953 this->write(to_string(i.value()));
954 }
955 }
956
writeFloatLiteral(const FloatLiteral & f)957 void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
958 this->write(to_string(f.value()));
959 }
960
writeSetting(const Setting & s)961 void GLSLCodeGenerator::writeSetting(const Setting& s) {
962 SK_ABORT("internal error; setting was not folded to a constant during compilation\n");
963 }
964
writeFunctionDeclaration(const FunctionDeclaration & f)965 void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) {
966 this->writeTypePrecision(f.returnType());
967 this->writeType(f.returnType());
968 this->write(" " + f.mangledName() + "(");
969 const char* separator = "";
970 for (const auto& param : f.parameters()) {
971 // This is a workaround for our test files. They use the runtime effect signature, so main
972 // takes a coords parameter. The IR generator tags those with a builtin ID (sk_FragCoord),
973 // and we omit them from the declaration here, so the function is valid GLSL.
974 if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) {
975 continue;
976 }
977 this->write(separator);
978 separator = ", ";
979 this->writeModifiers(param->modifiers(), false);
980 std::vector<int> sizes;
981 const Type* type = ¶m->type();
982 if (type->isArray()) {
983 sizes.push_back(type->columns());
984 type = &type->componentType();
985 }
986 this->writeTypePrecision(*type);
987 this->writeType(*type);
988 this->write(" " + param->name());
989 for (int s : sizes) {
990 if (s == Type::kUnsizedArray) {
991 this->write("[]");
992 } else {
993 this->write("[" + to_string(s) + "]");
994 }
995 }
996 }
997 this->write(")");
998 }
999
writeFunction(const FunctionDefinition & f)1000 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1001 fSetupFragPositionLocal = false;
1002 fSetupFragCoordWorkaround = false;
1003
1004 this->writeFunctionDeclaration(f.declaration());
1005 this->writeLine(" {");
1006 fIndentation++;
1007
1008 fFunctionHeader.clear();
1009 OutputStream* oldOut = fOut;
1010 StringStream buffer;
1011 fOut = &buffer;
1012 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
1013 if (!stmt->isEmpty()) {
1014 this->writeStatement(*stmt);
1015 this->finishLine();
1016 }
1017 }
1018
1019 fIndentation--;
1020 this->writeLine("}");
1021
1022 fOut = oldOut;
1023 this->write(fFunctionHeader);
1024 this->write(buffer.str());
1025 }
1026
writeFunctionPrototype(const FunctionPrototype & f)1027 void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
1028 this->writeFunctionDeclaration(f.declaration());
1029 this->writeLine(";");
1030 }
1031
writeModifiers(const Modifiers & modifiers,bool globalContext)1032 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
1033 bool globalContext) {
1034 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1035 this->write("flat ");
1036 }
1037 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1038 this->write("noperspective ");
1039 }
1040 String layout = modifiers.fLayout.description();
1041 if (layout.size()) {
1042 this->write(layout + " ");
1043 }
1044 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
1045 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1046 this->write("inout ");
1047 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
1048 if (globalContext &&
1049 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1050 this->write(fProgram.fConfig->fKind == ProgramKind::kVertex ? "attribute "
1051 : "varying ");
1052 } else {
1053 this->write("in ");
1054 }
1055 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1056 if (globalContext &&
1057 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
1058 this->write("varying ");
1059 } else {
1060 this->write("out ");
1061 }
1062 }
1063 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1064 this->write("uniform ");
1065 }
1066 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1067 this->write("const ");
1068 }
1069 }
1070
writeInterfaceBlock(const InterfaceBlock & intf)1071 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1072 if (intf.typeName() == "sk_PerVertex") {
1073 return;
1074 }
1075 this->writeModifiers(intf.variable().modifiers(), true);
1076 this->writeLine(intf.typeName() + " {");
1077 fIndentation++;
1078 const Type* structType = &intf.variable().type();
1079 if (structType->isArray()) {
1080 structType = &structType->componentType();
1081 }
1082 for (const auto& f : structType->fields()) {
1083 this->writeModifiers(f.fModifiers, false);
1084 this->writeTypePrecision(*f.fType);
1085 this->writeType(*f.fType);
1086 this->writeLine(" " + f.fName + ";");
1087 }
1088 fIndentation--;
1089 this->write("}");
1090 if (intf.instanceName().size()) {
1091 this->write(" ");
1092 this->write(intf.instanceName());
1093 if (intf.arraySize() > 0) {
1094 this->write("[");
1095 this->write(to_string(intf.arraySize()));
1096 this->write("]");
1097 } else if (intf.arraySize() == Type::kUnsizedArray){
1098 this->write("[]");
1099 }
1100 }
1101 this->writeLine(";");
1102 }
1103
writeVarInitializer(const Variable & var,const Expression & value)1104 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1105 this->writeExpression(value, Precedence::kTopLevel);
1106 }
1107
getTypePrecision(const Type & type)1108 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1109 if (usesPrecisionModifiers()) {
1110 switch (type.typeKind()) {
1111 case Type::TypeKind::kScalar:
1112 if (type == *fContext.fTypes.fShort || type == *fContext.fTypes.fUShort) {
1113 if (fProgram.fConfig->fSettings.fForceHighPrecision ||
1114 this->caps().incompleteShortIntPrecision()) {
1115 return "highp ";
1116 }
1117 return "mediump ";
1118 }
1119 if (type == *fContext.fTypes.fHalf) {
1120 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
1121 }
1122 if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fInt ||
1123 type == *fContext.fTypes.fUInt) {
1124 return "highp ";
1125 }
1126 return "";
1127 case Type::TypeKind::kVector: // fall through
1128 case Type::TypeKind::kMatrix:
1129 case Type::TypeKind::kArray:
1130 return this->getTypePrecision(type.componentType());
1131 default:
1132 break;
1133 }
1134 }
1135 return "";
1136 }
1137
writeTypePrecision(const Type & type)1138 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1139 this->write(this->getTypePrecision(type));
1140 }
1141
writeVarDeclaration(const VarDeclaration & var,bool global)1142 void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
1143 this->writeModifiers(var.var().modifiers(), global);
1144 this->writeTypePrecision(var.baseType());
1145 this->writeType(var.baseType());
1146 this->write(" ");
1147 this->write(var.var().name());
1148 if (var.arraySize() > 0) {
1149 this->write("[");
1150 this->write(to_string(var.arraySize()));
1151 this->write("]");
1152 } else if (var.arraySize() == Type::kUnsizedArray){
1153 this->write("[]");
1154 }
1155 if (var.value()) {
1156 this->write(" = ");
1157 this->writeVarInitializer(var.var(), *var.value());
1158 }
1159 if (!fFoundExternalSamplerDecl && var.var().type() == *fContext.fTypes.fSamplerExternalOES) {
1160 if (this->caps().externalTextureExtensionString()) {
1161 this->writeExtension(this->caps().externalTextureExtensionString());
1162 }
1163 if (this->caps().secondExternalTextureExtensionString()) {
1164 this->writeExtension(this->caps().secondExternalTextureExtensionString());
1165 }
1166 fFoundExternalSamplerDecl = true;
1167 }
1168 if (!fFoundRectSamplerDecl && var.var().type() == *fContext.fTypes.fSampler2DRect) {
1169 fFoundRectSamplerDecl = true;
1170 }
1171 this->write(";");
1172 }
1173
writeStatement(const Statement & s)1174 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1175 switch (s.kind()) {
1176 case Statement::Kind::kBlock:
1177 this->writeBlock(s.as<Block>());
1178 break;
1179 case Statement::Kind::kExpression:
1180 this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
1181 this->write(";");
1182 break;
1183 case Statement::Kind::kReturn:
1184 this->writeReturnStatement(s.as<ReturnStatement>());
1185 break;
1186 case Statement::Kind::kVarDeclaration:
1187 this->writeVarDeclaration(s.as<VarDeclaration>(), false);
1188 break;
1189 case Statement::Kind::kIf:
1190 this->writeIfStatement(s.as<IfStatement>());
1191 break;
1192 case Statement::Kind::kFor:
1193 this->writeForStatement(s.as<ForStatement>());
1194 break;
1195 case Statement::Kind::kDo:
1196 this->writeDoStatement(s.as<DoStatement>());
1197 break;
1198 case Statement::Kind::kSwitch:
1199 this->writeSwitchStatement(s.as<SwitchStatement>());
1200 break;
1201 case Statement::Kind::kBreak:
1202 this->write("break;");
1203 break;
1204 case Statement::Kind::kContinue:
1205 this->write("continue;");
1206 break;
1207 case Statement::Kind::kDiscard:
1208 this->write("discard;");
1209 break;
1210 case Statement::Kind::kInlineMarker:
1211 case Statement::Kind::kNop:
1212 this->write(";");
1213 break;
1214 default:
1215 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
1216 break;
1217 }
1218 }
1219
writeBlock(const Block & b)1220 void GLSLCodeGenerator::writeBlock(const Block& b) {
1221 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1222 // something here to make the code valid).
1223 bool isScope = b.isScope() || b.isEmpty();
1224 if (isScope) {
1225 this->writeLine("{");
1226 fIndentation++;
1227 }
1228 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1229 if (!stmt->isEmpty()) {
1230 this->writeStatement(*stmt);
1231 this->finishLine();
1232 }
1233 }
1234 if (isScope) {
1235 fIndentation--;
1236 this->write("}");
1237 }
1238 }
1239
writeIfStatement(const IfStatement & stmt)1240 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1241 this->write("if (");
1242 this->writeExpression(*stmt.test(), Precedence::kTopLevel);
1243 this->write(") ");
1244 this->writeStatement(*stmt.ifTrue());
1245 if (stmt.ifFalse()) {
1246 this->write(" else ");
1247 this->writeStatement(*stmt.ifFalse());
1248 }
1249 }
1250
writeForStatement(const ForStatement & f)1251 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1252 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1253 if (!f.initializer() && f.test() && !f.next()) {
1254 this->write("while (");
1255 this->writeExpression(*f.test(), Precedence::kTopLevel);
1256 this->write(") ");
1257 this->writeStatement(*f.statement());
1258 return;
1259 }
1260
1261 this->write("for (");
1262 if (f.initializer() && !f.initializer()->isEmpty()) {
1263 this->writeStatement(*f.initializer());
1264 } else {
1265 this->write("; ");
1266 }
1267 if (f.test()) {
1268 if (this->caps().addAndTrueToLoopCondition()) {
1269 std::unique_ptr<Expression> and_true(new BinaryExpression(
1270 /*offset=*/-1, f.test()->clone(), Token::Kind::TK_LOGICALAND,
1271 BoolLiteral::Make(fContext, /*offset=*/-1, /*value=*/true),
1272 fContext.fTypes.fBool.get()));
1273 this->writeExpression(*and_true, Precedence::kTopLevel);
1274 } else {
1275 this->writeExpression(*f.test(), Precedence::kTopLevel);
1276 }
1277 }
1278 this->write("; ");
1279 if (f.next()) {
1280 this->writeExpression(*f.next(), Precedence::kTopLevel);
1281 }
1282 this->write(") ");
1283 this->writeStatement(*f.statement());
1284 }
1285
writeDoStatement(const DoStatement & d)1286 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1287 if (!this->caps().rewriteDoWhileLoops()) {
1288 this->write("do ");
1289 this->writeStatement(*d.statement());
1290 this->write(" while (");
1291 this->writeExpression(*d.test(), Precedence::kTopLevel);
1292 this->write(");");
1293 return;
1294 }
1295
1296 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1297 // do {
1298 // CODE;
1299 // } while (CONDITION)
1300 //
1301 // to loops of the form
1302 // bool temp = false;
1303 // while (true) {
1304 // if (temp) {
1305 // if (!CONDITION) {
1306 // break;
1307 // }
1308 // }
1309 // temp = true;
1310 // CODE;
1311 // }
1312 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1313 this->write("bool ");
1314 this->write(tmpVar);
1315 this->writeLine(" = false;");
1316 this->writeLine("while (true) {");
1317 fIndentation++;
1318 this->write("if (");
1319 this->write(tmpVar);
1320 this->writeLine(") {");
1321 fIndentation++;
1322 this->write("if (!");
1323 this->writeExpression(*d.test(), Precedence::kPrefix);
1324 this->writeLine(") {");
1325 fIndentation++;
1326 this->writeLine("break;");
1327 fIndentation--;
1328 this->writeLine("}");
1329 fIndentation--;
1330 this->writeLine("}");
1331 this->write(tmpVar);
1332 this->writeLine(" = true;");
1333 this->writeStatement(*d.statement());
1334 this->finishLine();
1335 fIndentation--;
1336 this->write("}");
1337 }
1338
writeSwitchStatement(const SwitchStatement & s)1339 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1340 this->write("switch (");
1341 this->writeExpression(*s.value(), Precedence::kTopLevel);
1342 this->writeLine(") {");
1343 fIndentation++;
1344 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1345 const SwitchCase& c = stmt->as<SwitchCase>();
1346 if (c.value()) {
1347 this->write("case ");
1348 this->writeExpression(*c.value(), Precedence::kTopLevel);
1349 this->writeLine(":");
1350 } else {
1351 this->writeLine("default:");
1352 }
1353 if (!c.statement()->isEmpty()) {
1354 fIndentation++;
1355 this->writeStatement(*c.statement());
1356 this->finishLine();
1357 fIndentation--;
1358 }
1359 }
1360 fIndentation--;
1361 this->finishLine();
1362 this->write("}");
1363 }
1364
writeReturnStatement(const ReturnStatement & r)1365 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1366 this->write("return");
1367 if (r.expression()) {
1368 this->write(" ");
1369 this->writeExpression(*r.expression(), Precedence::kTopLevel);
1370 }
1371 this->write(";");
1372 }
1373
writeHeader()1374 void GLSLCodeGenerator::writeHeader() {
1375 if (this->caps().versionDeclString()) {
1376 this->write(this->caps().versionDeclString());
1377 this->finishLine();
1378 }
1379 }
1380
writeProgramElement(const ProgramElement & e)1381 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1382 switch (e.kind()) {
1383 case ProgramElement::Kind::kExtension:
1384 this->writeExtension(e.as<Extension>().name());
1385 break;
1386 case ProgramElement::Kind::kGlobalVar: {
1387 const VarDeclaration& decl =
1388 e.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
1389 int builtin = decl.var().modifiers().fLayout.fBuiltin;
1390 if (builtin == -1) {
1391 // normal var
1392 this->writeVarDeclaration(decl, true);
1393 this->finishLine();
1394 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1395 this->caps().mustDeclareFragmentShaderOutput()) {
1396 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
1397 this->write("inout ");
1398 } else {
1399 this->write("out ");
1400 }
1401 if (usesPrecisionModifiers()) {
1402 this->write("mediump ");
1403 }
1404 this->writeLine("vec4 sk_FragColor;");
1405 }
1406 break;
1407 }
1408 case ProgramElement::Kind::kInterfaceBlock:
1409 this->writeInterfaceBlock(e.as<InterfaceBlock>());
1410 break;
1411 case ProgramElement::Kind::kFunction:
1412 this->writeFunction(e.as<FunctionDefinition>());
1413 break;
1414 case ProgramElement::Kind::kFunctionPrototype:
1415 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1416 break;
1417 case ProgramElement::Kind::kModifiers: {
1418 const Modifiers& modifiers = e.as<ModifiersDeclaration>().modifiers();
1419 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1420 if (this->caps().gsInvocationsExtensionString()) {
1421 this->writeExtension(this->caps().gsInvocationsExtensionString());
1422 }
1423 fFoundGSInvocations = true;
1424 }
1425 this->writeModifiers(modifiers, true);
1426 this->writeLine(";");
1427 break;
1428 }
1429 case ProgramElement::Kind::kEnum:
1430 break;
1431 case ProgramElement::Kind::kStructDefinition:
1432 this->writeStructDefinition(e.as<StructDefinition>());
1433 break;
1434 default:
1435 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1436 break;
1437 }
1438 }
1439
writeInputVars()1440 void GLSLCodeGenerator::writeInputVars() {
1441 if (fProgram.fInputs.fRTHeight) {
1442 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1443 fGlobals.writeText("uniform ");
1444 fGlobals.writeText(precision);
1445 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1446 }
1447 }
1448
generateCode()1449 bool GLSLCodeGenerator::generateCode() {
1450 this->writeHeader();
1451 if (fProgram.fConfig->fKind == ProgramKind::kGeometry &&
1452 this->caps().geometryShaderExtensionString()) {
1453 this->writeExtension(this->caps().geometryShaderExtensionString());
1454 }
1455 OutputStream* rawOut = fOut;
1456 StringStream body;
1457 fOut = &body;
1458 // Write all the program elements except for functions.
1459 for (const ProgramElement* e : fProgram.elements()) {
1460 if (!e->is<FunctionDefinition>()) {
1461 this->writeProgramElement(*e);
1462 }
1463 }
1464 // Write the functions last.
1465 // Why don't we write things in their original order? Because the Inliner likes to move function
1466 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
1467 // that the code relies on.
1468 for (const ProgramElement* e : fProgram.elements()) {
1469 if (e->is<FunctionDefinition>()) {
1470 this->writeProgramElement(*e);
1471 }
1472 }
1473 fOut = rawOut;
1474
1475 write_stringstream(fExtensions, *rawOut);
1476 this->writeInputVars();
1477 write_stringstream(fGlobals, *rawOut);
1478
1479 if (!this->caps().canUseFragCoord()) {
1480 Layout layout;
1481 switch (fProgram.fConfig->fKind) {
1482 case ProgramKind::kVertex: {
1483 Modifiers modifiers(layout, Modifiers::kOut_Flag);
1484 this->writeModifiers(modifiers, true);
1485 if (this->usesPrecisionModifiers()) {
1486 this->write("highp ");
1487 }
1488 this->write("vec4 sk_FragCoord_Workaround;\n");
1489 break;
1490 }
1491 case ProgramKind::kFragment: {
1492 Modifiers modifiers(layout, Modifiers::kIn_Flag);
1493 this->writeModifiers(modifiers, true);
1494 if (this->usesPrecisionModifiers()) {
1495 this->write("highp ");
1496 }
1497 this->write("vec4 sk_FragCoord_Workaround;\n");
1498 break;
1499 }
1500 default:
1501 break;
1502 }
1503 }
1504
1505 if (this->usesPrecisionModifiers()) {
1506 this->writeLine("precision mediump float;");
1507 this->writeLine("precision mediump sampler2D;");
1508 if (fFoundExternalSamplerDecl &&
1509 !this->caps().noDefaultPrecisionForExternalSamplers()) {
1510 this->writeLine("precision mediump samplerExternalOES;");
1511 }
1512 if (fFoundRectSamplerDecl) {
1513 this->writeLine("precision mediump sampler2DRect;");
1514 }
1515 }
1516 write_stringstream(fExtraFunctions, *rawOut);
1517 write_stringstream(body, *rawOut);
1518 return 0 == fErrors.errorCount();
1519 }
1520
1521 } // namespace SkSL
1522