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