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