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 "include/core/SkSpan.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/base/SkTArray.h"
13 #include "src/base/SkEnumBitMask.h"
14 #include "src/base/SkNoDestructor.h"
15 #include "src/base/SkStringView.h"
16 #include "src/core/SkTHash.h"
17 #include "src/core/SkTraceEvent.h"
18 #include "src/sksl/SkSLAnalysis.h"
19 #include "src/sksl/SkSLBuiltinTypes.h"
20 #include "src/sksl/SkSLCompiler.h"
21 #include "src/sksl/SkSLContext.h"
22 #include "src/sksl/SkSLDefines.h"
23 #include "src/sksl/SkSLErrorReporter.h"
24 #include "src/sksl/SkSLGLSL.h"
25 #include "src/sksl/SkSLIntrinsicList.h"
26 #include "src/sksl/SkSLOperator.h"
27 #include "src/sksl/SkSLOutputStream.h"
28 #include "src/sksl/SkSLPosition.h"
29 #include "src/sksl/SkSLProgramSettings.h"
30 #include "src/sksl/SkSLString.h"
31 #include "src/sksl/SkSLStringStream.h"
32 #include "src/sksl/SkSLUtil.h"
33 #include "src/sksl/codegen/SkSLCodeGenTypes.h"
34 #include "src/sksl/codegen/SkSLCodeGenerator.h"
35 #include "src/sksl/ir/SkSLBinaryExpression.h"
36 #include "src/sksl/ir/SkSLBlock.h"
37 #include "src/sksl/ir/SkSLConstructor.h"
38 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
39 #include "src/sksl/ir/SkSLConstructorCompound.h"
40 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
41 #include "src/sksl/ir/SkSLDoStatement.h"
42 #include "src/sksl/ir/SkSLExpression.h"
43 #include "src/sksl/ir/SkSLExpressionStatement.h"
44 #include "src/sksl/ir/SkSLExtension.h"
45 #include "src/sksl/ir/SkSLFieldAccess.h"
46 #include "src/sksl/ir/SkSLForStatement.h"
47 #include "src/sksl/ir/SkSLFunctionCall.h"
48 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
49 #include "src/sksl/ir/SkSLFunctionDefinition.h"
50 #include "src/sksl/ir/SkSLFunctionPrototype.h"
51 #include "src/sksl/ir/SkSLIRNode.h"
52 #include "src/sksl/ir/SkSLIfStatement.h"
53 #include "src/sksl/ir/SkSLIndexExpression.h"
54 #include "src/sksl/ir/SkSLInterfaceBlock.h"
55 #include "src/sksl/ir/SkSLLayout.h"
56 #include "src/sksl/ir/SkSLLiteral.h"
57 #include "src/sksl/ir/SkSLModifierFlags.h"
58 #include "src/sksl/ir/SkSLModifiersDeclaration.h"
59 #include "src/sksl/ir/SkSLPostfixExpression.h"
60 #include "src/sksl/ir/SkSLPrefixExpression.h"
61 #include "src/sksl/ir/SkSLProgram.h"
62 #include "src/sksl/ir/SkSLProgramElement.h"
63 #include "src/sksl/ir/SkSLReturnStatement.h"
64 #include "src/sksl/ir/SkSLSetting.h"
65 #include "src/sksl/ir/SkSLStatement.h"
66 #include "src/sksl/ir/SkSLStructDefinition.h"
67 #include "src/sksl/ir/SkSLSwitchCase.h"
68 #include "src/sksl/ir/SkSLSwitchStatement.h"
69 #include "src/sksl/ir/SkSLSwizzle.h"
70 #include "src/sksl/ir/SkSLTernaryExpression.h"
71 #include "src/sksl/ir/SkSLType.h"
72 #include "src/sksl/ir/SkSLVarDeclarations.h"
73 #include "src/sksl/ir/SkSLVariable.h"
74 #include "src/sksl/ir/SkSLVariableReference.h"
75 #include "src/sksl/spirv.h"
76
77 #include <cstddef>
78 #include <cstdint>
79 #include <initializer_list>
80 #include <memory>
81 #include <string_view>
82 #include <vector>
83
84 using namespace skia_private;
85
86 namespace SkSL {
87
88 class GLSLCodeGenerator final : public CodeGenerator {
89 public:
GLSLCodeGenerator(const Context * context,const ShaderCaps * caps,const Program * program,OutputStream * out,PrettyPrint pp)90 GLSLCodeGenerator(const Context* context,
91 const ShaderCaps* caps,
92 const Program* program,
93 OutputStream* out,
94 PrettyPrint pp)
95 : CodeGenerator(context, caps, program, out), fPrettyPrint(pp) {}
96
97 bool generateCode() override;
98
99 protected:
100 using Precedence = OperatorPrecedence;
101
102 void write(std::string_view s);
103
104 void writeLine(std::string_view s = std::string_view());
105
106 void finishLine();
107
108 void writeHeader();
109
110 bool usesPrecisionModifiers() const;
111
112 void writeIdentifier(std::string_view identifier);
113
114 std::string getTypeName(const Type& type);
115
116 void writeStructDefinition(const StructDefinition& s);
117
118 void writeType(const Type& type);
119
120 void writeExtension(std::string_view name, bool require = true);
121
122 void writeInterfaceBlock(const InterfaceBlock& intf);
123
124 void writeFunctionDeclaration(const FunctionDeclaration& f);
125
126 void writeFunctionPrototype(const FunctionPrototype& f);
127
128 void writeFunction(const FunctionDefinition& f);
129
130 void writeLayout(const Layout& layout);
131
132 void writeModifiers(const Layout& layout, ModifierFlags flags, bool globalContext);
133
134 void writeInputVars();
135
136 void writeVarInitializer(const Variable& var, const Expression& value);
137
138 const char* getTypePrecision(const Type& type);
139
140 void writeTypePrecision(const Type& type);
141
142 void writeGlobalVarDeclaration(const GlobalVarDeclaration& e);
143
144 void writeVarDeclaration(const VarDeclaration& var, bool global);
145
146 void writeFragCoord();
147
148 void writeVariableReference(const VariableReference& ref);
149
150 void writeExpression(const Expression& expr, Precedence parentPrecedence);
151
152 void writeIntrinsicCall(const FunctionCall& c);
153
154 void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
155
156 void writeDeterminantHack(const Expression& mat);
157
158 void writeInverseHack(const Expression& mat);
159
160 void writeTransposeHack(const Expression& mat);
161
162 void writeInverseSqrtHack(const Expression& x);
163
164 void writeMatrixComparisonWorkaround(const BinaryExpression& x);
165
166 void writeFunctionCall(const FunctionCall& c);
167
168 void writeConstructorCompound(const ConstructorCompound& c, Precedence parentPrecedence);
169
170 void writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
171 Precedence parentPrecedence);
172
173 void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
174
175 void writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence);
176
177 void writeFieldAccess(const FieldAccess& f);
178
179 void writeSwizzle(const Swizzle& swizzle);
180
181 void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
182
183 void writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
184 Precedence parentPrecedence);
185
186 void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
187
188 void writeIndexExpression(const IndexExpression& expr);
189
190 void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
191
192 void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
193
194 void writeLiteral(const Literal& l);
195
196 void writeStatement(const Statement& s);
197
198 void writeBlock(const Block& b);
199
200 void writeIfStatement(const IfStatement& stmt);
201
202 void writeForStatement(const ForStatement& f);
203
204 void writeDoStatement(const DoStatement& d);
205
206 void writeExpressionStatement(const ExpressionStatement& s);
207
208 void writeSwitchStatement(const SwitchStatement& s);
209
210 void writeReturnStatement(const ReturnStatement& r);
211
212 void writeProgramElement(const ProgramElement& e);
213
214 bool shouldRewriteVoidTypedFunctions(const FunctionDeclaration* func) const;
215
216 StringStream fExtensions;
217 StringStream fGlobals;
218 StringStream fExtraFunctions;
219 std::string fFunctionHeader;
220 int fVarCount = 0;
221 int fIndentation = 0;
222 bool fAtLineStart = false;
223 const FunctionDeclaration* fCurrentFunction = nullptr;
224
225 // true if we have run into usages of dFdx / dFdy
226 bool fFoundDerivatives = false;
227 bool fFoundExternalSamplerDecl = false;
228 bool fFoundRectSamplerDecl = false;
229 bool fSetupClockwise = false;
230 bool fSetupFragPosition = false;
231 bool fSetupFragCoordWorkaround = false;
232 PrettyPrint fPrettyPrint;
233
234 // Workaround/polyfill flags
235 bool fWrittenAbsEmulation = false;
236 bool fWrittenDeterminant2 = false, fWrittenDeterminant3 = false, fWrittenDeterminant4 = false;
237 bool fWrittenInverse2 = false, fWrittenInverse3 = false, fWrittenInverse4 = false;
238 bool fWrittenTranspose[3][3] = {};
239 };
240
write(std::string_view s)241 void GLSLCodeGenerator::write(std::string_view s) {
242 if (s.empty()) {
243 return;
244 }
245 if (fAtLineStart && fPrettyPrint == PrettyPrint::kYes) {
246 for (int i = 0; i < fIndentation; i++) {
247 fOut->writeText(" ");
248 }
249 }
250 fOut->write(s.data(), s.length());
251 fAtLineStart = false;
252 }
253
writeLine(std::string_view s)254 void GLSLCodeGenerator::writeLine(std::string_view s) {
255 this->write(s);
256 fOut->writeText("\n");
257 fAtLineStart = true;
258 }
259
finishLine()260 void GLSLCodeGenerator::finishLine() {
261 if (!fAtLineStart) {
262 this->writeLine();
263 }
264 }
265
writeExtension(std::string_view name,bool require)266 void GLSLCodeGenerator::writeExtension(std::string_view name, bool require) {
267 fExtensions.writeText("#extension ");
268 fExtensions.write(name.data(), name.length());
269 fExtensions.writeText(require ? " : require\n" : " : enable\n");
270 }
271
usesPrecisionModifiers() const272 bool GLSLCodeGenerator::usesPrecisionModifiers() const {
273 return fCaps.fUsesPrecisionModifiers;
274 }
275
is_reserved_identifier(std::string_view identifier)276 static bool is_reserved_identifier(std::string_view identifier) {
277 // This list was taken from https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
278 // in section 3.6, "Keywords." Built-in types, and entries that our parser already recognizes as
279 // reserved or otherwise non-identifiers, have been eliminated.
280 using ReservedWordSet = THashSet<std::string_view>;
281 static const SkNoDestructor<ReservedWordSet> kAllReservedWords(ReservedWordSet{
282 "active",
283 "centroid",
284 "coherent",
285 "common",
286 "filter",
287 "partition",
288 "patch",
289 "precise",
290 "resource",
291 "restrict",
292 "shared",
293 "smooth",
294 "subroutine",
295 });
296
297 return kAllReservedWords->contains(identifier);
298 }
299
writeIdentifier(std::string_view identifier)300 void GLSLCodeGenerator::writeIdentifier(std::string_view identifier) {
301 // GLSL forbids two underscores in a row.
302 // If an identifier contains "__" or "_X", replace each "_" in the identifier with "_X".
303 if (skstd::contains(identifier, "__") || skstd::contains(identifier, "_X")) {
304 for (const char c : identifier) {
305 if (c == '_') {
306 this->write("_X");
307 } else {
308 this->write(std::string_view(&c, 1));
309 }
310 }
311 } else {
312 if (is_reserved_identifier(identifier)) {
313 this->write("_skReserved_");
314 }
315 this->write(identifier);
316 }
317 }
318
319 // Returns the name of the type with array dimensions, e.g. `float[2]`.
getTypeName(const Type & raw)320 std::string GLSLCodeGenerator::getTypeName(const Type& raw) {
321 const Type& type = raw.resolve().scalarTypeForLiteral();
322 switch (type.typeKind()) {
323 case Type::TypeKind::kVector: {
324 const Type& component = type.componentType();
325 std::string result;
326 if (component.matches(*fContext.fTypes.fFloat) ||
327 component.matches(*fContext.fTypes.fHalf)) {
328 result = "vec";
329 }
330 else if (component.isSigned()) {
331 result = "ivec";
332 }
333 else if (component.isUnsigned()) {
334 result = "uvec";
335 }
336 else if (component.matches(*fContext.fTypes.fBool)) {
337 result = "bvec";
338 }
339 else {
340 SK_ABORT("unsupported vector type");
341 }
342 result += std::to_string(type.columns());
343 return result;
344 }
345 case Type::TypeKind::kMatrix: {
346 std::string result;
347 const Type& component = type.componentType();
348 if (component.matches(*fContext.fTypes.fFloat) ||
349 component.matches(*fContext.fTypes.fHalf)) {
350 result = "mat";
351 }
352 else {
353 SK_ABORT("unsupported matrix type");
354 }
355 result += std::to_string(type.columns());
356 if (type.columns() != type.rows()) {
357 result += "x";
358 result += std::to_string(type.rows());
359 }
360 return result;
361 }
362 case Type::TypeKind::kArray: {
363 std::string baseTypeName = this->getTypeName(type.componentType());
364 if (type.isUnsizedArray()) {
365 return String::printf("%s[]", baseTypeName.c_str());
366 }
367 return String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
368 }
369 case Type::TypeKind::kScalar: {
370 if (type.matches(*fContext.fTypes.fHalf)) {
371 return "float";
372 }
373 else if (type.matches(*fContext.fTypes.fShort)) {
374 return "int";
375 }
376 else if (type.matches(*fContext.fTypes.fUShort)) {
377 return "uint";
378 }
379
380 return std::string(type.name());
381 }
382 default:
383 return std::string(type.name());
384 }
385 }
386
writeStructDefinition(const StructDefinition & s)387 void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) {
388 const Type& type = s.type();
389 this->write("struct ");
390 this->writeIdentifier(type.name());
391 this->writeLine(" {");
392 fIndentation++;
393 for (const auto& f : type.fields()) {
394 this->writeModifiers(f.fLayout, f.fModifierFlags, /*globalContext=*/false);
395 this->writeTypePrecision(*f.fType);
396 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
397 this->writeType(baseType);
398 this->write(" ");
399 this->writeIdentifier(f.fName);
400 if (f.fType->isArray()) {
401 this->write("[" + std::to_string(f.fType->columns()) + "]");
402 }
403 this->writeLine(";");
404 }
405 fIndentation--;
406 this->writeLine("};");
407 }
408
writeType(const Type & type)409 void GLSLCodeGenerator::writeType(const Type& type) {
410 this->writeIdentifier(this->getTypeName(type));
411 }
412
writeExpression(const Expression & expr,Precedence parentPrecedence)413 void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
414 switch (expr.kind()) {
415 case Expression::Kind::kBinary:
416 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
417 break;
418 case Expression::Kind::kConstructorDiagonalMatrix:
419 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
420 parentPrecedence);
421 break;
422 case Expression::Kind::kConstructorArrayCast:
423 this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence);
424 break;
425 case Expression::Kind::kConstructorCompound:
426 this->writeConstructorCompound(expr.as<ConstructorCompound>(), parentPrecedence);
427 break;
428 case Expression::Kind::kConstructorArray:
429 case Expression::Kind::kConstructorMatrixResize:
430 case Expression::Kind::kConstructorSplat:
431 case Expression::Kind::kConstructorStruct:
432 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
433 break;
434 case Expression::Kind::kConstructorScalarCast:
435 case Expression::Kind::kConstructorCompoundCast:
436 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
437 break;
438 case Expression::Kind::kEmpty:
439 this->write("false");
440 break;
441 case Expression::Kind::kFieldAccess:
442 this->writeFieldAccess(expr.as<FieldAccess>());
443 break;
444 case Expression::Kind::kFunctionCall:
445 this->writeFunctionCall(expr.as<FunctionCall>());
446 break;
447 case Expression::Kind::kLiteral:
448 this->writeLiteral(expr.as<Literal>());
449 break;
450 case Expression::Kind::kPrefix:
451 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
452 break;
453 case Expression::Kind::kPostfix:
454 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
455 break;
456 case Expression::Kind::kSetting:
457 this->writeExpression(*expr.as<Setting>().toLiteral(fCaps), parentPrecedence);
458 break;
459 case Expression::Kind::kSwizzle:
460 this->writeSwizzle(expr.as<Swizzle>());
461 break;
462 case Expression::Kind::kVariableReference:
463 this->writeVariableReference(expr.as<VariableReference>());
464 break;
465 case Expression::Kind::kTernary:
466 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
467 break;
468 case Expression::Kind::kIndex:
469 this->writeIndexExpression(expr.as<IndexExpression>());
470 break;
471 default:
472 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
473 break;
474 }
475 }
476
is_abs(Expression & expr)477 static bool is_abs(Expression& expr) {
478 return expr.is<FunctionCall>() &&
479 expr.as<FunctionCall>().function().intrinsicKind() == k_abs_IntrinsicKind;
480 }
481
482 // turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
483 // Tegra3 compiler bug.
writeMinAbsHack(Expression & absExpr,Expression & otherExpr)484 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
485 SkASSERT(!fCaps.fCanUseMinAndAbsTogether);
486 std::string tmpVar1 = "minAbsHackVar" + std::to_string(fVarCount++);
487 std::string tmpVar2 = "minAbsHackVar" + std::to_string(fVarCount++);
488 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(absExpr.type()) +
489 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
490 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(otherExpr.type()) +
491 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
492 this->write("((" + tmpVar1 + " = ");
493 this->writeExpression(absExpr, Precedence::kAssignment);
494 this->write(") < (" + tmpVar2 + " = ");
495 this->writeExpression(otherExpr, Precedence::kAssignment);
496 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
497 }
498
writeInverseSqrtHack(const Expression & x)499 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
500 this->write("(1.0 / sqrt(");
501 this->writeExpression(x, Precedence::kExpression);
502 this->write("))");
503 }
504
505 static constexpr char kDeterminant2[] = R"(
506 float _determinant2(mat2 m) {
507 return m[0].x*m[1].y - m[0].y*m[1].x;
508 }
509 )";
510
511 static constexpr char kDeterminant3[] = R"(
512 float _determinant3(mat3 m) {
513 float
514 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
515 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
516 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
517 b01 = a22*a11 - a12*a21,
518 b11 =-a22*a10 + a12*a20,
519 b21 = a21*a10 - a11*a20;
520 return a00*b01 + a01*b11 + a02*b21;
521 }
522 )";
523
524 static constexpr char kDeterminant4[] = R"(
525 mat4 _determinant4(mat4 m) {
526 float
527 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z, a03 = m[0].w,
528 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z, a13 = m[1].w,
529 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z, a23 = m[2].w,
530 a30 = m[3].x, a31 = m[3].y, a32 = m[3].z, a33 = m[3].w,
531 b00 = a00*a11 - a01*a10,
532 b01 = a00*a12 - a02*a10,
533 b02 = a00*a13 - a03*a10,
534 b03 = a01*a12 - a02*a11,
535 b04 = a01*a13 - a03*a11,
536 b05 = a02*a13 - a03*a12,
537 b06 = a20*a31 - a21*a30,
538 b07 = a20*a32 - a22*a30,
539 b08 = a20*a33 - a23*a30,
540 b09 = a21*a32 - a22*a31,
541 b10 = a21*a33 - a23*a31,
542 b11 = a22*a33 - a23*a32;
543 return b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06;
544 }
545 )";
546
writeDeterminantHack(const Expression & mat)547 void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
548 const Type& type = mat.type();
549 if (type.matches(*fContext.fTypes.fFloat2x2) ||
550 type.matches(*fContext.fTypes.fHalf2x2)) {
551 this->write("_determinant2(");
552 if (!fWrittenDeterminant2) {
553 fWrittenDeterminant2 = true;
554 fExtraFunctions.writeText(kDeterminant2);
555 }
556 } else if (type.matches(*fContext.fTypes.fFloat3x3) ||
557 type.matches(*fContext.fTypes.fHalf3x3)) {
558 this->write("_determinant3(");
559 if (!fWrittenDeterminant3) {
560 fWrittenDeterminant3 = true;
561 fExtraFunctions.writeText(kDeterminant3);
562 }
563 } else if (type.matches(*fContext.fTypes.fFloat4x4) ||
564 type.matches(*fContext.fTypes.fHalf4x4)) {
565 this->write("_determinant4(");
566 if (!fWrittenDeterminant4) {
567 fWrittenDeterminant4 = true;
568 fExtraFunctions.writeText(kDeterminant4);
569 }
570 } else {
571 SkDEBUGFAILF("no polyfill for determinant(%s)", type.description().c_str());
572 this->write("determinant(");
573 }
574 this->writeExpression(mat, Precedence::kExpression);
575 this->write(")");
576 }
577
578 static constexpr char kInverse2[] = R"(
579 mat2 _inverse2(mat2 m) {
580 return mat2(m[1].y, -m[0].y, -m[1].x, m[0].x) / (m[0].x * m[1].y - m[0].y * m[1].x);
581 }
582 )";
583
584 static constexpr char kInverse3[] = R"(
585 mat3 _inverse3(mat3 m) {
586 float
587 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
588 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
589 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
590 b01 = a22*a11 - a12*a21,
591 b11 =-a22*a10 + a12*a20,
592 b21 = a21*a10 - a11*a20,
593 det = a00*b01 + a01*b11 + a02*b21;
594 return mat3(
595 b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),
596 b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),
597 b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) / det;
598 }
599 )";
600
601 static constexpr char kInverse4[] = R"(
602 mat4 _inverse4(mat4 m) {
603 float
604 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z, a03 = m[0].w,
605 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z, a13 = m[1].w,
606 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z, a23 = m[2].w,
607 a30 = m[3].x, a31 = m[3].y, a32 = m[3].z, a33 = m[3].w,
608 b00 = a00*a11 - a01*a10,
609 b01 = a00*a12 - a02*a10,
610 b02 = a00*a13 - a03*a10,
611 b03 = a01*a12 - a02*a11,
612 b04 = a01*a13 - a03*a11,
613 b05 = a02*a13 - a03*a12,
614 b06 = a20*a31 - a21*a30,
615 b07 = a20*a32 - a22*a30,
616 b08 = a20*a33 - a23*a30,
617 b09 = a21*a32 - a22*a31,
618 b10 = a21*a33 - a23*a31,
619 b11 = a22*a33 - a23*a32,
620 det = b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06;
621 return mat4(
622 a11*b11 - a12*b10 + a13*b09,
623 a02*b10 - a01*b11 - a03*b09,
624 a31*b05 - a32*b04 + a33*b03,
625 a22*b04 - a21*b05 - a23*b03,
626 a12*b08 - a10*b11 - a13*b07,
627 a00*b11 - a02*b08 + a03*b07,
628 a32*b02 - a30*b05 - a33*b01,
629 a20*b05 - a22*b02 + a23*b01,
630 a10*b10 - a11*b08 + a13*b06,
631 a01*b08 - a00*b10 - a03*b06,
632 a30*b04 - a31*b02 + a33*b00,
633 a21*b02 - a20*b04 - a23*b00,
634 a11*b07 - a10*b09 - a12*b06,
635 a00*b09 - a01*b07 + a02*b06,
636 a31*b01 - a30*b03 - a32*b00,
637 a20*b03 - a21*b01 + a22*b00) / det;
638 }
639 )";
640
writeInverseHack(const Expression & mat)641 void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
642 const Type& type = mat.type();
643 if (type.matches(*fContext.fTypes.fFloat2x2) || type.matches(*fContext.fTypes.fHalf2x2)) {
644 this->write("_inverse2(");
645 if (!fWrittenInverse2) {
646 fWrittenInverse2 = true;
647 fExtraFunctions.writeText(kInverse2);
648 }
649 } else if (type.matches(*fContext.fTypes.fFloat3x3) ||
650 type.matches(*fContext.fTypes.fHalf3x3)) {
651 this->write("_inverse3(");
652 if (!fWrittenInverse3) {
653 fWrittenInverse3 = true;
654 fExtraFunctions.writeText(kInverse3);
655 }
656 } else if (type.matches(*fContext.fTypes.fFloat4x4) ||
657 type.matches(*fContext.fTypes.fHalf4x4)) {
658 this->write("_inverse4(");
659 if (!fWrittenInverse4) {
660 fWrittenInverse4 = true;
661 fExtraFunctions.writeText(kInverse4);
662 }
663 } else {
664 SkDEBUGFAILF("no polyfill for inverse(%s)", type.description().c_str());
665 this->write("inverse(");
666 }
667 this->writeExpression(mat, Precedence::kExpression);
668 this->write(")");
669 }
670
writeTransposeHack(const Expression & mat)671 void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
672 const Type& type = mat.type();
673 int c = type.columns();
674 int r = type.rows();
675 std::string name = "transpose" + std::to_string(c) + std::to_string(r);
676
677 SkASSERT(c >= 2 && c <= 4);
678 SkASSERT(r >= 2 && r <= 4);
679 bool* writtenThisTranspose = &fWrittenTranspose[c - 2][r - 2];
680 if (!*writtenThisTranspose) {
681 *writtenThisTranspose = true;
682 std::string typeName = this->getTypeName(type);
683 const Type& base = type.componentType();
684 std::string transposed = this->getTypeName(base.toCompound(fContext, r, c));
685 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) { return " +
686 transposed + "(").c_str());
687 auto separator = SkSL::String::Separator();
688 for (int row = 0; row < r; ++row) {
689 for (int column = 0; column < c; ++column) {
690 fExtraFunctions.writeText(separator().c_str());
691 fExtraFunctions.writeText(("m[" + std::to_string(column) + "][" +
692 std::to_string(row) + "]").c_str());
693 }
694 }
695 fExtraFunctions.writeText("); }\n");
696 }
697 this->write(name + "(");
698 this->writeExpression(mat, Precedence::kExpression);
699 this->write(")");
700 }
701
writeFunctionCall(const FunctionCall & c)702 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
703 const FunctionDeclaration& function = c.function();
704 const ExpressionArray& arguments = c.arguments();
705 bool isTextureFunctionWithBias = false;
706 bool nameWritten = false;
707 const char* closingParen = ")";
708 switch (c.function().intrinsicKind()) {
709 case k_abs_IntrinsicKind: {
710 if (!fCaps.fEmulateAbsIntFunction)
711 break;
712 SkASSERT(arguments.size() == 1);
713 if (!arguments[0]->type().matches(*fContext.fTypes.fInt)) {
714 break;
715 }
716 // abs(int) on Intel OSX is incorrect, so emulate it:
717 this->write("_absemulation");
718 nameWritten = true;
719 if (!fWrittenAbsEmulation) {
720 fWrittenAbsEmulation = true;
721 fExtraFunctions.writeText("int _absemulation(int x) { return x * sign(x); }\n");
722 }
723 break;
724 }
725 case k_atan_IntrinsicKind:
726 if (fCaps.fMustForceNegatedAtanParamToFloat &&
727 arguments.size() == 2 &&
728 arguments[1]->is<PrefixExpression>()) {
729 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
730 if (p.getOperator().kind() == Operator::Kind::MINUS) {
731 this->write("atan(");
732 this->writeExpression(*arguments[0], Precedence::kSequence);
733 this->write(", -1.0 * ");
734 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
735 this->write(")");
736 return;
737 }
738 }
739 break;
740 case k_ldexp_IntrinsicKind:
741 if (fCaps.fMustForceNegatedLdexpParamToMultiply &&
742 arguments.size() == 2 &&
743 arguments[1]->is<PrefixExpression>()) {
744 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
745 if (p.getOperator().kind() == Operator::Kind::MINUS) {
746 this->write("ldexp(");
747 this->writeExpression(*arguments[0], Precedence::kSequence);
748 this->write(", ");
749 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
750 this->write(" * -1)");
751 return;
752 }
753 }
754 break;
755 case k_dFdy_IntrinsicKind:
756 // Flipping Y also negates the Y derivatives.
757 closingParen = "))";
758 this->write("(");
759 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
760 this->write(SKSL_RTFLIP_NAME ".y * ");
761 }
762 this->write("dFdy");
763 nameWritten = true;
764 [[fallthrough]];
765 case k_dFdx_IntrinsicKind:
766 case k_fwidth_IntrinsicKind:
767 if (!fFoundDerivatives &&
768 fCaps.shaderDerivativeExtensionString()) {
769 this->writeExtension(fCaps.shaderDerivativeExtensionString());
770 fFoundDerivatives = true;
771 }
772 break;
773 case k_determinant_IntrinsicKind:
774 if (!fCaps.fBuiltinDeterminantSupport) {
775 SkASSERT(arguments.size() == 1);
776 this->writeDeterminantHack(*arguments[0]);
777 return;
778 }
779 break;
780 case k_fma_IntrinsicKind:
781 if (!fCaps.fBuiltinFMASupport) {
782 SkASSERT(arguments.size() == 3);
783 this->write("((");
784 this->writeExpression(*arguments[0], Precedence::kSequence);
785 this->write(") * (");
786 this->writeExpression(*arguments[1], Precedence::kSequence);
787 this->write(") + (");
788 this->writeExpression(*arguments[2], Precedence::kSequence);
789 this->write("))");
790 return;
791 }
792 break;
793 case k_fract_IntrinsicKind:
794 if (!fCaps.fCanUseFractForNegativeValues) {
795 SkASSERT(arguments.size() == 1);
796 this->write("(0.5 - sign(");
797 this->writeExpression(*arguments[0], Precedence::kSequence);
798 this->write(") * (0.5 - fract(abs(");
799 this->writeExpression(*arguments[0], Precedence::kSequence);
800 this->write("))))");
801 return;
802 }
803 break;
804 case k_inverse_IntrinsicKind:
805 if (fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k140) {
806 SkASSERT(arguments.size() == 1);
807 this->writeInverseHack(*arguments[0]);
808 return;
809 }
810 break;
811 case k_inversesqrt_IntrinsicKind:
812 if (fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
813 SkASSERT(arguments.size() == 1);
814 this->writeInverseSqrtHack(*arguments[0]);
815 return;
816 }
817 break;
818 case k_min_IntrinsicKind:
819 if (!fCaps.fCanUseMinAndAbsTogether) {
820 SkASSERT(arguments.size() == 2);
821 if (is_abs(*arguments[0])) {
822 this->writeMinAbsHack(*arguments[0], *arguments[1]);
823 return;
824 }
825 if (is_abs(*arguments[1])) {
826 // note that this violates the GLSL left-to-right evaluation semantics.
827 // I doubt it will ever end up mattering, but it's worth calling out.
828 this->writeMinAbsHack(*arguments[1], *arguments[0]);
829 return;
830 }
831 }
832 break;
833 case k_pow_IntrinsicKind:
834 if (!fCaps.fRemovePowWithConstantExponent) {
835 break;
836 }
837 // pow(x, y) on some NVIDIA drivers causes crashes if y is a constant.
838 // It's hard to tell what constitutes "constant" here, so just replace in all cases.
839
840 // Change pow(x, y) into exp2(y * log2(x))
841 this->write("exp2(");
842 this->writeExpression(*arguments[1], Precedence::kMultiplicative);
843 this->write(" * log2(");
844 this->writeExpression(*arguments[0], Precedence::kSequence);
845 this->write("))");
846 return;
847 case k_saturate_IntrinsicKind:
848 SkASSERT(arguments.size() == 1);
849 this->write("clamp(");
850 this->writeExpression(*arguments[0], Precedence::kSequence);
851 this->write(", 0.0, 1.0)");
852 return;
853 case k_sample_IntrinsicKind: {
854 const char* dim = "";
855 bool proj = false;
856 const Type& arg0Type = arguments[0]->type();
857 const Type& arg1Type = arguments[1]->type();
858 switch (arg0Type.dimensions()) {
859 case SpvDim1D:
860 dim = "1D";
861 isTextureFunctionWithBias = true;
862 if (arg1Type.matches(*fContext.fTypes.fFloat)) {
863 proj = false;
864 } else {
865 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat2));
866 proj = true;
867 }
868 break;
869 case SpvDim2D:
870 dim = "2D";
871 if (!arg0Type.matches(*fContext.fTypes.fSamplerExternalOES)) {
872 isTextureFunctionWithBias = true;
873 }
874 if (arg1Type.matches(*fContext.fTypes.fFloat2)) {
875 proj = false;
876 } else {
877 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat3));
878 proj = true;
879 }
880 break;
881 case SpvDim3D:
882 dim = "3D";
883 isTextureFunctionWithBias = true;
884 if (arg1Type.matches(*fContext.fTypes.fFloat3)) {
885 proj = false;
886 } else {
887 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat4));
888 proj = true;
889 }
890 break;
891 case SpvDimCube:
892 dim = "Cube";
893 isTextureFunctionWithBias = true;
894 proj = false;
895 break;
896 case SpvDimRect:
897 dim = "2DRect";
898 proj = false;
899 break;
900 case SpvDimBuffer:
901 SkASSERT(false); // doesn't exist
902 dim = "Buffer";
903 proj = false;
904 break;
905 case SpvDimSubpassData:
906 SkASSERT(false); // doesn't exist
907 dim = "SubpassData";
908 proj = false;
909 break;
910 }
911 this->write("texture");
912 if (fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
913 this->write(dim);
914 }
915 if (proj) {
916 this->write("Proj");
917 }
918 nameWritten = true;
919 break;
920 }
921 case k_sampleGrad_IntrinsicKind: {
922 SkASSERT(arguments.size() == 4);
923 this->write("textureGrad");
924 nameWritten = true;
925 break;
926 }
927 case k_sampleLod_IntrinsicKind: {
928 SkASSERT(arguments.size() == 3);
929 this->write("textureLod");
930 nameWritten = true;
931 break;
932 }
933 case k_transpose_IntrinsicKind:
934 if (fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
935 SkASSERT(arguments.size() == 1);
936 this->writeTransposeHack(*arguments[0]);
937 return;
938 }
939 break;
940 default:
941 break;
942 }
943
944 if (!nameWritten) {
945 this->writeIdentifier(function.mangledName());
946 }
947 this->write("(");
948 auto separator = SkSL::String::Separator();
949 for (const auto& arg : arguments) {
950 this->write(separator());
951 this->writeExpression(*arg, Precedence::kSequence);
952 }
953 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
954 this->write(String::printf(", %g", kSharpenTexturesBias));
955 }
956 this->write(closingParen);
957 }
958
writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix & c,Precedence parentPrecedence)959 void GLSLCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
960 Precedence parentPrecedence) {
961 if (c.type().columns() == 4 && c.type().rows() == 2) {
962 // Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2
963 // matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646)
964 // We can work around this issue by multiplying a scalar by the identity matrix.
965 // In practice, this doesn't come up naturally in real code and we don't know every affected
966 // driver, so we just apply this workaround everywhere.
967 this->write("(");
968 this->writeType(c.type());
969 this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * ");
970 this->writeExpression(*c.argument(), Precedence::kMultiplicative);
971 this->write(")");
972 return;
973 }
974 this->writeAnyConstructor(c, parentPrecedence);
975 }
976
writeConstructorCompound(const ConstructorCompound & c,Precedence parentPrecedence)977 void GLSLCodeGenerator::writeConstructorCompound(const ConstructorCompound& c,
978 Precedence parentPrecedence) {
979 // If this is a 2x2 matrix constructor containing a single argument...
980 if (c.type().isMatrix() && c.arguments().size() == 1) {
981 // ... and that argument is a vec4...
982 const Expression& expr = *c.arguments().front();
983 if (expr.type().isVector() && expr.type().columns() == 4) {
984 // ... let's rewrite the cast to dodge issues on very old GPUs. (skia:13559)
985 if (Analysis::IsTrivialExpression(expr)) {
986 this->writeType(c.type());
987 this->write("(");
988 this->writeExpression(expr, Precedence::kPostfix);
989 this->write(".xy, ");
990 this->writeExpression(expr, Precedence::kPostfix);
991 this->write(".zw)");
992 } else {
993 std::string tempVec = "_tempVec" + std::to_string(fVarCount++);
994 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(expr.type()) +
995 this->getTypeName(expr.type()) + " " + tempVec + ";\n";
996 this->write("((");
997 this->write(tempVec);
998 this->write(" = ");
999 this->writeExpression(expr, Precedence::kAssignment);
1000 this->write("), ");
1001 this->writeType(c.type());
1002 this->write("(");
1003 this->write(tempVec);
1004 this->write(".xy, ");
1005 this->write(tempVec);
1006 this->write(".zw))");
1007 }
1008 return;
1009 }
1010 }
1011 this->writeAnyConstructor(c, parentPrecedence);
1012 }
1013
writeCastConstructor(const AnyConstructor & c,Precedence parentPrecedence)1014 void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
1015 const auto arguments = c.argumentSpan();
1016 SkASSERT(arguments.size() == 1);
1017
1018 const Expression& argument = *arguments.front();
1019 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
1020 (argument.type().matches(*fContext.fTypes.fFloatLiteral)))) {
1021 // In cases like half(float), they're different types as far as SkSL is concerned but
1022 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
1023 // writing out the inner expression here.
1024 this->writeExpression(argument, parentPrecedence);
1025 return;
1026 }
1027
1028 // This cast should be emitted as-is.
1029 return this->writeAnyConstructor(c, parentPrecedence);
1030 }
1031
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)1032 void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
1033 this->writeType(c.type());
1034 this->write("(");
1035 auto separator = SkSL::String::Separator();
1036 for (const auto& arg : c.argumentSpan()) {
1037 this->write(separator());
1038 this->writeExpression(*arg, Precedence::kSequence);
1039 }
1040 this->write(")");
1041 }
1042
writeFragCoord()1043 void GLSLCodeGenerator::writeFragCoord() {
1044 if (!fCaps.fCanUseFragCoord) {
1045 if (!fSetupFragCoordWorkaround) {
1046 const char* precision = this->usesPrecisionModifiers() ? "highp " : "";
1047 fFunctionHeader += precision;
1048 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
1049 fFunctionHeader += precision;
1050 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
1051 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
1052 // Ensure that we get exact .5 values for x and y.
1053 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
1054 "vec2(.5);\n";
1055 fSetupFragCoordWorkaround = true;
1056 }
1057 this->write("sk_FragCoord_Resolved");
1058 return;
1059 }
1060
1061 if (!fSetupFragPosition) {
1062 fFunctionHeader += this->usesPrecisionModifiers() ? "highp " : "";
1063 fFunctionHeader += " vec4 sk_FragCoord = vec4("
1064 "gl_FragCoord.x, ";
1065 if (fProgram.fConfig->fSettings.fForceNoRTFlip) {
1066 fFunctionHeader += "gl_FragCoord.y, ";
1067 } else {
1068 fFunctionHeader += SKSL_RTFLIP_NAME ".x + " SKSL_RTFLIP_NAME ".y * gl_FragCoord.y, ";
1069 }
1070 fFunctionHeader +=
1071 "gl_FragCoord.z, "
1072 "gl_FragCoord.w);\n";
1073 fSetupFragPosition = true;
1074 }
1075 this->write("sk_FragCoord");
1076 }
1077
writeVariableReference(const VariableReference & ref)1078 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
1079 switch (ref.variable()->layout().fBuiltin) {
1080 case SK_FRAGCOLOR_BUILTIN:
1081 if (fCaps.mustDeclareFragmentShaderOutput()) {
1082 this->write("sk_FragColor");
1083 } else {
1084 this->write("gl_FragColor");
1085 }
1086 break;
1087 case SK_SECONDARYFRAGCOLOR_BUILTIN:
1088 if (fCaps.fDualSourceBlendingSupport) {
1089 this->write("gl_SecondaryFragColorEXT");
1090 } else {
1091 fContext.fErrors->error(ref.position(), "'sk_SecondaryFragColor' not supported");
1092 }
1093 break;
1094 case SK_FRAGCOORD_BUILTIN:
1095 this->writeFragCoord();
1096 break;
1097 case SK_CLOCKWISE_BUILTIN:
1098 if (!fSetupClockwise) {
1099 fFunctionHeader += " bool sk_Clockwise = gl_FrontFacing;\n";
1100 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
1101 fFunctionHeader += " if (" SKSL_RTFLIP_NAME ".y < 0.0) {\n"
1102 " sk_Clockwise = !sk_Clockwise;\n"
1103 " }\n";
1104 }
1105 fSetupClockwise = true;
1106 }
1107 this->write("sk_Clockwise");
1108 break;
1109 case SK_VERTEXID_BUILTIN:
1110 this->write("gl_VertexID");
1111 break;
1112 case SK_INSTANCEID_BUILTIN:
1113 this->write("gl_InstanceID");
1114 break;
1115 case SK_LASTFRAGCOLOR_BUILTIN:
1116 if (fCaps.fFBFetchColorName) {
1117 this->write(fCaps.fFBFetchColorName);
1118 } else {
1119 fContext.fErrors->error(ref.position(), "'sk_LastFragColor' not supported");
1120 }
1121 break;
1122 case SK_SAMPLEMASKIN_BUILTIN:
1123 // GLSL defines gl_SampleMaskIn as an array of ints. SkSL defines it as a scalar uint.
1124 this->write("uint(gl_SampleMaskIn[0])");
1125 break;
1126 case SK_SAMPLEMASK_BUILTIN:
1127 // GLSL defines gl_SampleMask as an array of ints. SkSL defines it as a scalar uint.
1128 this->write("gl_SampleMask[0]");
1129 break;
1130 default:
1131 this->writeIdentifier(ref.variable()->mangledName());
1132 break;
1133 }
1134 }
1135
writeIndexExpression(const IndexExpression & expr)1136 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
1137 this->writeExpression(*expr.base(), Precedence::kPostfix);
1138 this->write("[");
1139 this->writeExpression(*expr.index(), Precedence::kExpression);
1140 this->write("]");
1141 }
1142
is_sk_position(const Expression & expr)1143 bool is_sk_position(const Expression& expr) {
1144 if (!expr.is<FieldAccess>()) {
1145 return false;
1146 }
1147 const FieldAccess& f = expr.as<FieldAccess>();
1148 return f.base()->type().fields()[f.fieldIndex()].fLayout.fBuiltin == SK_POSITION_BUILTIN;
1149 }
1150
is_sk_samplemask(const Expression & expr)1151 bool is_sk_samplemask(const Expression& expr) {
1152 if (!expr.is<VariableReference>()) {
1153 return false;
1154 }
1155 const VariableReference& v = expr.as<VariableReference>();
1156 return v.variable()->layout().fBuiltin == SK_SAMPLEMASK_BUILTIN;
1157 }
1158
writeFieldAccess(const FieldAccess & f)1159 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
1160 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
1161 this->writeExpression(*f.base(), Precedence::kPostfix);
1162 this->write(".");
1163 }
1164 const Type& baseType = f.base()->type();
1165 int builtin = baseType.fields()[f.fieldIndex()].fLayout.fBuiltin;
1166 if (builtin == SK_POSITION_BUILTIN) {
1167 this->write("gl_Position");
1168 } else if (builtin == SK_POINTSIZE_BUILTIN) {
1169 this->write("gl_PointSize");
1170 } else {
1171 this->writeIdentifier(baseType.fields()[f.fieldIndex()].fName);
1172 }
1173 }
1174
writeSwizzle(const Swizzle & swizzle)1175 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
1176 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
1177 this->write(".");
1178 this->write(Swizzle::MaskString(swizzle.components()));
1179 }
1180
writeMatrixComparisonWorkaround(const BinaryExpression & b)1181 void GLSLCodeGenerator::writeMatrixComparisonWorkaround(const BinaryExpression& b) {
1182 const Expression& left = *b.left();
1183 const Expression& right = *b.right();
1184 Operator op = b.getOperator();
1185
1186 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
1187 SkASSERT(left.type().isMatrix());
1188 SkASSERT(right.type().isMatrix());
1189
1190 std::string tempMatrix1 = "_tempMatrix" + std::to_string(fVarCount++);
1191 std::string tempMatrix2 = "_tempMatrix" + std::to_string(fVarCount++);
1192
1193 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(left.type()) +
1194 this->getTypeName(left.type()) + " " + tempMatrix1 + ";\n " +
1195 this->getTypePrecision(right.type()) +
1196 this->getTypeName(right.type()) + " " + tempMatrix2 + ";\n";
1197 this->write("((" + tempMatrix1 + " = ");
1198 this->writeExpression(left, Precedence::kAssignment);
1199 this->write("), (" + tempMatrix2 + " = ");
1200 this->writeExpression(right, Precedence::kAssignment);
1201 this->write("), (" + tempMatrix1);
1202 this->write(op.operatorName());
1203 this->write(tempMatrix2 + "))");
1204 }
1205
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)1206 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
1207 Precedence parentPrecedence) {
1208 const Expression& left = *b.left();
1209 const Expression& right = *b.right();
1210 Operator op = b.getOperator();
1211 if (fCaps.fUnfoldShortCircuitAsTernary && (op.kind() == Operator::Kind::LOGICALAND ||
1212 op.kind() == Operator::Kind::LOGICALOR)) {
1213 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
1214 return;
1215 }
1216
1217 if (fCaps.fRewriteMatrixComparisons && left.type().isMatrix() &&
1218 right.type().isMatrix() && op.isEquality()) {
1219 this->writeMatrixComparisonWorkaround(b);
1220 return;
1221 }
1222
1223 Precedence precedence = op.getBinaryPrecedence();
1224 if (precedence >= parentPrecedence) {
1225 this->write("(");
1226 }
1227 const bool needsPositionWorkaround = ProgramConfig::IsVertex(fProgram.fConfig->fKind) &&
1228 op.isAssignment() &&
1229 is_sk_position(left) &&
1230 !Analysis::ContainsRTAdjust(right) &&
1231 !fCaps.fCanUseFragCoord;
1232 if (needsPositionWorkaround) {
1233 this->write("sk_FragCoord_Workaround = (");
1234 }
1235 this->writeExpression(left, precedence);
1236 this->write(op.operatorName());
1237
1238 const bool isAssignmentToSampleMask = ProgramConfig::IsFragment(fProgram.fConfig->fKind) &&
1239 op.isAssignment() &&
1240 is_sk_samplemask(left);
1241 if (isAssignmentToSampleMask) {
1242 // GLSL defines the sample masks as signed ints; SkSL (and Metal/WebGPU) use unsigned ints.
1243 this->write("int(");
1244 }
1245 this->writeExpression(right, precedence);
1246 if (isAssignmentToSampleMask) {
1247 this->write(")");
1248 }
1249 if (needsPositionWorkaround) {
1250 this->write(")");
1251 }
1252 if (precedence >= parentPrecedence) {
1253 this->write(")");
1254 }
1255 }
1256
writeShortCircuitWorkaroundExpression(const BinaryExpression & b,Precedence parentPrecedence)1257 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
1258 Precedence parentPrecedence) {
1259 if (Precedence::kTernary >= parentPrecedence) {
1260 this->write("(");
1261 }
1262
1263 // Transform:
1264 // a && b => a ? b : false
1265 // a || b => a ? true : b
1266 this->writeExpression(*b.left(), Precedence::kTernary);
1267 this->write(" ? ");
1268 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
1269 this->writeExpression(*b.right(), Precedence::kTernary);
1270 } else {
1271 Literal boolTrue(Position(), /*value=*/1, fContext.fTypes.fBool.get());
1272 this->writeLiteral(boolTrue);
1273 }
1274 this->write(" : ");
1275 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
1276 Literal boolFalse(Position(), /*value=*/0, fContext.fTypes.fBool.get());
1277 this->writeLiteral(boolFalse);
1278 } else {
1279 this->writeExpression(*b.right(), Precedence::kTernary);
1280 }
1281 if (Precedence::kTernary >= parentPrecedence) {
1282 this->write(")");
1283 }
1284 }
1285
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)1286 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
1287 Precedence parentPrecedence) {
1288 if (Precedence::kTernary >= parentPrecedence) {
1289 this->write("(");
1290 }
1291 this->writeExpression(*t.test(), Precedence::kTernary);
1292 this->write(" ? ");
1293 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
1294 this->write(" : ");
1295 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
1296 if (Precedence::kTernary >= parentPrecedence) {
1297 this->write(")");
1298 }
1299 }
1300
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)1301 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
1302 Precedence parentPrecedence) {
1303 if (Precedence::kPrefix >= parentPrecedence) {
1304 this->write("(");
1305 }
1306 this->write(p.getOperator().tightOperatorName());
1307 this->writeExpression(*p.operand(), Precedence::kPrefix);
1308 if (Precedence::kPrefix >= parentPrecedence) {
1309 this->write(")");
1310 }
1311 }
1312
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)1313 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
1314 Precedence parentPrecedence) {
1315 if (Precedence::kPostfix >= parentPrecedence) {
1316 this->write("(");
1317 }
1318 this->writeExpression(*p.operand(), Precedence::kPostfix);
1319 this->write(p.getOperator().tightOperatorName());
1320 if (Precedence::kPostfix >= parentPrecedence) {
1321 this->write(")");
1322 }
1323 }
1324
writeLiteral(const Literal & l)1325 void GLSLCodeGenerator::writeLiteral(const Literal& l) {
1326 const Type& type = l.type();
1327 if (type.isInteger()) {
1328 if (type.matches(*fContext.fTypes.fUInt)) {
1329 this->write(std::to_string(l.intValue() & 0xffffffff) + "u");
1330 } else if (type.matches(*fContext.fTypes.fUShort)) {
1331 this->write(std::to_string(l.intValue() & 0xffff) + "u");
1332 } else {
1333 this->write(std::to_string(l.intValue()));
1334 }
1335 return;
1336 }
1337 this->write(l.description(OperatorPrecedence::kExpression));
1338 }
1339
shouldRewriteVoidTypedFunctions(const FunctionDeclaration * func) const1340 bool GLSLCodeGenerator::shouldRewriteVoidTypedFunctions(const FunctionDeclaration* func) const {
1341 // We can change void-typed user functions to return a (meaningless) float so that sequence
1342 // expressions will work normally in WebGL2. (skbug.com/294893925)
1343 return func &&
1344 !func->isMain() &&
1345 func->returnType().isVoid() &&
1346 !fCaps.fCanUseVoidInSequenceExpressions;
1347 }
1348
writeFunctionDeclaration(const FunctionDeclaration & f)1349 void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) {
1350 if (this->shouldRewriteVoidTypedFunctions(&f)) {
1351 this->write("float ");
1352 } else {
1353 this->writeTypePrecision(f.returnType());
1354 this->writeType(f.returnType());
1355 this->write(" ");
1356 }
1357 this->writeIdentifier(f.mangledName());
1358 this->write("(");
1359 auto separator = SkSL::String::Separator();
1360 for (size_t index = 0; index < f.parameters().size(); ++index) {
1361 const Variable* param = f.parameters()[index];
1362
1363 // This is a workaround for our test files. They use the runtime effect signature, so main
1364 // takes a coords parameter. We detect these at IR generation time, and we omit them from
1365 // the declaration here, so the function is valid GLSL. (Well, valid as long as the
1366 // coordinates aren't actually referenced.)
1367 if (f.isMain() && param == f.getMainCoordsParameter()) {
1368 continue;
1369 }
1370 this->write(separator());
1371 ModifierFlags flags = param->modifierFlags();
1372 if (fCaps.fRemoveConstFromFunctionParameters) {
1373 flags &= ~ModifierFlag::kConst;
1374 }
1375 this->writeModifiers(param->layout(), flags, /*globalContext=*/false);
1376 std::vector<int> sizes;
1377 const Type* type = ¶m->type();
1378 if (type->isArray()) {
1379 sizes.push_back(type->columns());
1380 type = &type->componentType();
1381 }
1382 this->writeTypePrecision(*type);
1383 this->writeType(*type);
1384 this->write(" ");
1385 if (!param->name().empty()) {
1386 this->writeIdentifier(param->mangledName());
1387 } else {
1388 // By the spec, GLSL does not require function parameters to be named (see
1389 // `single_declaration` in the Shading Language Grammar), but some older versions of
1390 // GLSL report "formal parameter lacks a name" if a parameter is not named.
1391 this->write("_skAnonymousParam");
1392 this->write(std::to_string(index));
1393 }
1394 for (int s : sizes) {
1395 this->write("[");
1396 if (s != Type::kUnsizedArray) {
1397 this->write(std::to_string(s));
1398 }
1399 this->write("]");
1400 }
1401 }
1402 this->write(")");
1403 }
1404
writeFunction(const FunctionDefinition & f)1405 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1406 fSetupFragPosition = false;
1407 fSetupFragCoordWorkaround = false;
1408 fSetupClockwise = false;
1409 fCurrentFunction = &f.declaration();
1410
1411 this->writeFunctionDeclaration(f.declaration());
1412 this->writeLine(" {");
1413 fIndentation++;
1414
1415 fFunctionHeader.clear();
1416 OutputStream* oldOut = fOut;
1417 StringStream buffer;
1418 fOut = &buffer;
1419 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
1420 if (!stmt->isEmpty()) {
1421 this->writeStatement(*stmt);
1422 this->finishLine();
1423 }
1424 }
1425
1426 if (this->shouldRewriteVoidTypedFunctions(&f.declaration())) {
1427 // If we can't use void in sequence expressions, we rewrite void-typed user functions to
1428 // return a (never-used) float in case they are used in a sequence expression.
1429 this->writeLine("return 0.0;");
1430 }
1431
1432 fIndentation--;
1433 this->writeLine("}");
1434
1435 fOut = oldOut;
1436 this->write(fFunctionHeader);
1437 this->write(buffer.str());
1438
1439 fCurrentFunction = nullptr;
1440 }
1441
writeFunctionPrototype(const FunctionPrototype & f)1442 void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
1443 this->writeFunctionDeclaration(f.declaration());
1444 this->writeLine(";");
1445 }
1446
writeModifiers(const Layout & layout,ModifierFlags flags,bool globalContext)1447 void GLSLCodeGenerator::writeModifiers(const Layout& layout,
1448 ModifierFlags flags,
1449 bool globalContext) {
1450 this->write(layout.paddedDescription());
1451
1452 // For GLSL 4.1 and below, qualifier-order matters! These are written out in Modifier-bit order.
1453 if (flags & ModifierFlag::kFlat) {
1454 this->write("flat ");
1455 }
1456 if (flags & ModifierFlag::kNoPerspective) {
1457 this->write("noperspective ");
1458 }
1459
1460 if (flags.isConst()) {
1461 this->write("const ");
1462 }
1463 if (flags.isUniform()) {
1464 this->write("uniform ");
1465 }
1466 if ((flags & ModifierFlag::kIn) && (flags & ModifierFlag::kOut)) {
1467 this->write("inout ");
1468 } else if (flags & ModifierFlag::kIn) {
1469 if (globalContext && fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
1470 this->write(ProgramConfig::IsVertex(fProgram.fConfig->fKind) ? "attribute "
1471 : "varying ");
1472 } else {
1473 this->write("in ");
1474 }
1475 } else if (flags & ModifierFlag::kOut) {
1476 if (globalContext && fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
1477 this->write("varying ");
1478 } else {
1479 this->write("out ");
1480 }
1481 }
1482
1483 if (flags.isReadOnly()) {
1484 this->write("readonly ");
1485 }
1486 if (flags.isWriteOnly()) {
1487 this->write("writeonly ");
1488 }
1489 if (flags.isBuffer()) {
1490 this->write("buffer ");
1491 }
1492 }
1493
writeInterfaceBlock(const InterfaceBlock & intf)1494 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1495 if (intf.typeName() == "sk_PerVertex") {
1496 return;
1497 }
1498 const Type* structType = &intf.var()->type().componentType();
1499 this->writeModifiers(intf.var()->layout(), intf.var()->modifierFlags(), /*globalContext=*/true);
1500 this->writeType(*structType);
1501 this->writeLine(" {");
1502 fIndentation++;
1503 for (const auto& f : structType->fields()) {
1504 this->writeModifiers(f.fLayout, f.fModifierFlags, /*globalContext=*/false);
1505 this->writeTypePrecision(*f.fType);
1506 this->writeType(*f.fType);
1507 this->write(" ");
1508 this->writeIdentifier(f.fName);
1509 this->writeLine(";");
1510 }
1511 fIndentation--;
1512 this->write("}");
1513 if (!intf.instanceName().empty()) {
1514 this->write(" ");
1515 this->writeIdentifier(intf.instanceName());
1516 if (intf.arraySize() > 0) {
1517 this->write("[");
1518 this->write(std::to_string(intf.arraySize()));
1519 this->write("]");
1520 }
1521 }
1522 this->writeLine(";");
1523 }
1524
writeVarInitializer(const Variable & var,const Expression & value)1525 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1526 this->writeExpression(value, Precedence::kExpression);
1527 }
1528
getTypePrecision(const Type & type)1529 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1530 if (this->usesPrecisionModifiers()) {
1531 switch (type.typeKind()) {
1532 case Type::TypeKind::kScalar:
1533 if (type.matches(*fContext.fTypes.fShort) ||
1534 type.matches(*fContext.fTypes.fUShort) ||
1535 type.matches(*fContext.fTypes.fHalf)) {
1536 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
1537 }
1538 if (type.matches(*fContext.fTypes.fFloat) ||
1539 type.matches(*fContext.fTypes.fInt) ||
1540 type.matches(*fContext.fTypes.fUInt)) {
1541 return "highp ";
1542 }
1543 return "";
1544 case Type::TypeKind::kVector: // fall through
1545 case Type::TypeKind::kMatrix:
1546 case Type::TypeKind::kArray:
1547 return this->getTypePrecision(type.componentType());
1548 default:
1549 break;
1550 }
1551 }
1552 return "";
1553 }
1554
writeTypePrecision(const Type & type)1555 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1556 this->write(this->getTypePrecision(type));
1557 }
1558
writeGlobalVarDeclaration(const GlobalVarDeclaration & e)1559 void GLSLCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& e) {
1560 const VarDeclaration& decl = e.as<GlobalVarDeclaration>().varDeclaration();
1561 switch (decl.var()->layout().fBuiltin) {
1562 case -1:
1563 // normal var
1564 this->writeVarDeclaration(decl, /*global=*/true);
1565 this->finishLine();
1566 break;
1567
1568 case SK_FRAGCOLOR_BUILTIN:
1569 if (fCaps.mustDeclareFragmentShaderOutput()) {
1570 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
1571 this->write("inout ");
1572 } else {
1573 this->write("out ");
1574 }
1575 if (this->usesPrecisionModifiers()) {
1576 this->write("mediump ");
1577 }
1578 this->writeLine("vec4 sk_FragColor;");
1579 }
1580 break;
1581
1582 default:
1583 break;
1584 }
1585 }
1586
writeVarDeclaration(const VarDeclaration & decl,bool global)1587 void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& decl, bool global) {
1588 const Variable* var = decl.var();
1589 this->writeModifiers(var->layout(), var->modifierFlags(), global);
1590
1591 if (global && !var->modifierFlags().isUniform()) {
1592 if (decl.baseType().typeKind() == Type::TypeKind::kSampler ||
1593 decl.baseType().typeKind() == Type::TypeKind::kSeparateSampler ||
1594 decl.baseType().typeKind() == Type::TypeKind::kTexture) {
1595 // We don't require the `uniform` modifier on textures/samplers, but GLSL does.
1596 this->write("uniform ");
1597 }
1598 }
1599
1600 this->writeTypePrecision(decl.baseType());
1601 this->writeType(decl.baseType());
1602 this->write(" ");
1603 this->writeIdentifier(var->mangledName());
1604 if (decl.arraySize() > 0) {
1605 this->write("[");
1606 this->write(std::to_string(decl.arraySize()));
1607 this->write("]");
1608 }
1609 if (decl.value()) {
1610 this->write(" = ");
1611 this->writeVarInitializer(*var, *decl.value());
1612 }
1613 if (!fFoundExternalSamplerDecl &&
1614 var->type().matches(*fContext.fTypes.fSamplerExternalOES)) {
1615 if (!fCaps.fExternalTextureSupport) {
1616 fContext.fErrors->error(decl.position(), "external texture support is not enabled");
1617 } else {
1618 if (fCaps.externalTextureExtensionString()) {
1619 this->writeExtension(fCaps.externalTextureExtensionString());
1620 }
1621 if (fCaps.secondExternalTextureExtensionString()) {
1622 this->writeExtension(fCaps.secondExternalTextureExtensionString());
1623 }
1624 fFoundExternalSamplerDecl = true;
1625 }
1626 }
1627 if (!fFoundRectSamplerDecl && var->type().matches(*fContext.fTypes.fSampler2DRect)) {
1628 fFoundRectSamplerDecl = true;
1629 }
1630 this->write(";");
1631 }
1632
writeStatement(const Statement & s)1633 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1634 switch (s.kind()) {
1635 case Statement::Kind::kBlock:
1636 this->writeBlock(s.as<Block>());
1637 break;
1638 case Statement::Kind::kExpression:
1639 this->writeExpressionStatement(s.as<ExpressionStatement>());
1640 break;
1641 case Statement::Kind::kReturn:
1642 this->writeReturnStatement(s.as<ReturnStatement>());
1643 break;
1644 case Statement::Kind::kVarDeclaration:
1645 this->writeVarDeclaration(s.as<VarDeclaration>(), /*global=*/false);
1646 break;
1647 case Statement::Kind::kIf:
1648 this->writeIfStatement(s.as<IfStatement>());
1649 break;
1650 case Statement::Kind::kFor:
1651 this->writeForStatement(s.as<ForStatement>());
1652 break;
1653 case Statement::Kind::kDo:
1654 this->writeDoStatement(s.as<DoStatement>());
1655 break;
1656 case Statement::Kind::kSwitch:
1657 this->writeSwitchStatement(s.as<SwitchStatement>());
1658 break;
1659 case Statement::Kind::kBreak:
1660 this->write("break;");
1661 break;
1662 case Statement::Kind::kContinue:
1663 this->write("continue;");
1664 break;
1665 case Statement::Kind::kDiscard:
1666 this->write("discard;");
1667 break;
1668 case Statement::Kind::kNop:
1669 this->write(";");
1670 break;
1671 default:
1672 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
1673 break;
1674 }
1675 }
1676
writeBlock(const Block & b)1677 void GLSLCodeGenerator::writeBlock(const Block& b) {
1678 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1679 // something here to make the code valid).
1680 bool isScope = b.isScope() || b.isEmpty();
1681 if (isScope) {
1682 this->writeLine("{");
1683 fIndentation++;
1684 }
1685 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1686 if (!stmt->isEmpty()) {
1687 this->writeStatement(*stmt);
1688 this->finishLine();
1689 }
1690 }
1691 if (isScope) {
1692 fIndentation--;
1693 this->write("}");
1694 }
1695 }
1696
writeIfStatement(const IfStatement & stmt)1697 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1698 this->write("if (");
1699 this->writeExpression(*stmt.test(), Precedence::kExpression);
1700 this->write(") ");
1701 this->writeStatement(*stmt.ifTrue());
1702 if (stmt.ifFalse()) {
1703 this->write(" else ");
1704 this->writeStatement(*stmt.ifFalse());
1705 }
1706 }
1707
writeForStatement(const ForStatement & f)1708 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1709 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1710 if (!f.initializer() && f.test() && !f.next()) {
1711 this->write("while (");
1712 this->writeExpression(*f.test(), Precedence::kExpression);
1713 this->write(") ");
1714 this->writeStatement(*f.statement());
1715 return;
1716 }
1717
1718 this->write("for (");
1719 if (f.initializer() && !f.initializer()->isEmpty()) {
1720 this->writeStatement(*f.initializer());
1721 } else {
1722 this->write("; ");
1723 }
1724 if (f.test()) {
1725 if (fCaps.fAddAndTrueToLoopCondition) {
1726 this->write("(");
1727 this->writeExpression(*f.test(), Precedence::kLogicalAnd);
1728 this->write(" && true)");
1729 } else {
1730 this->writeExpression(*f.test(), Precedence::kExpression);
1731 }
1732 }
1733 this->write("; ");
1734 if (f.next()) {
1735 this->writeExpression(*f.next(), Precedence::kExpression);
1736 }
1737 this->write(") ");
1738 this->writeStatement(*f.statement());
1739 }
1740
writeDoStatement(const DoStatement & d)1741 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1742 if (!fCaps.fRewriteDoWhileLoops) {
1743 this->write("do ");
1744 this->writeStatement(*d.statement());
1745 this->write(" while (");
1746 this->writeExpression(*d.test(), Precedence::kExpression);
1747 this->write(");");
1748 return;
1749 }
1750
1751 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1752 // do {
1753 // CODE;
1754 // } while (CONDITION)
1755 //
1756 // to loops of the form
1757 // bool temp = false;
1758 // while (true) {
1759 // if (temp) {
1760 // if (!CONDITION) {
1761 // break;
1762 // }
1763 // }
1764 // temp = true;
1765 // CODE;
1766 // }
1767 std::string tmpVar = "_tmpLoopSeenOnce" + std::to_string(fVarCount++);
1768 this->write("bool ");
1769 this->write(tmpVar);
1770 this->writeLine(" = false;");
1771 this->writeLine("while (true) {");
1772 fIndentation++;
1773 this->write("if (");
1774 this->write(tmpVar);
1775 this->writeLine(") {");
1776 fIndentation++;
1777 this->write("if (!");
1778 this->writeExpression(*d.test(), Precedence::kPrefix);
1779 this->writeLine(") {");
1780 fIndentation++;
1781 this->writeLine("break;");
1782 fIndentation--;
1783 this->writeLine("}");
1784 fIndentation--;
1785 this->writeLine("}");
1786 this->write(tmpVar);
1787 this->writeLine(" = true;");
1788 this->writeStatement(*d.statement());
1789 this->finishLine();
1790 fIndentation--;
1791 this->write("}");
1792 }
1793
writeExpressionStatement(const ExpressionStatement & s)1794 void GLSLCodeGenerator::writeExpressionStatement(const ExpressionStatement& s) {
1795 if (fProgram.fConfig->fSettings.fOptimize && !Analysis::HasSideEffects(*s.expression())) {
1796 // Don't emit dead expressions.
1797 return;
1798 }
1799 this->writeExpression(*s.expression(), Precedence::kStatement);
1800 this->write(";");
1801 }
1802
writeSwitchStatement(const SwitchStatement & s)1803 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1804 if (fCaps.fRewriteSwitchStatements) {
1805 std::string fallthroughVar = "_tmpSwitchFallthrough" + std::to_string(fVarCount++);
1806 std::string valueVar = "_tmpSwitchValue" + std::to_string(fVarCount++);
1807 std::string loopVar = "_tmpSwitchLoop" + std::to_string(fVarCount++);
1808 this->write("int ");
1809 this->write(valueVar);
1810 this->write(" = ");
1811 this->writeExpression(*s.value(), Precedence::kAssignment);
1812 this->write(", ");
1813 this->write(fallthroughVar);
1814 this->writeLine(" = 0;");
1815 this->write("for (int ");
1816 this->write(loopVar);
1817 this->write(" = 0; ");
1818 this->write(loopVar);
1819 this->write(" < 1; ");
1820 this->write(loopVar);
1821 this->writeLine("++) {");
1822 fIndentation++;
1823
1824 bool firstCase = true;
1825 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1826 const SwitchCase& c = stmt->as<SwitchCase>();
1827 if (!c.isDefault()) {
1828 this->write("if ((");
1829 if (firstCase) {
1830 firstCase = false;
1831 } else {
1832 this->write(fallthroughVar);
1833 this->write(" > 0) || (");
1834 }
1835 this->write(valueVar);
1836 this->write(" == ");
1837 this->write(std::to_string(c.value()));
1838 this->writeLine(")) {");
1839 fIndentation++;
1840
1841 // We write the entire case-block statement here, and then set `switchFallthrough`
1842 // to 1. If the case-block had a break statement in it, we break out of the outer
1843 // for-loop entirely, meaning the `switchFallthrough` assignment never occurs, nor
1844 // does any code after it inside the switch. We've forbidden `continue` statements
1845 // inside switch case-blocks entirely, so we don't need to consider their effect on
1846 // control flow; see the Finalizer in FunctionDefinition::Convert.
1847 this->writeStatement(*c.statement());
1848 this->finishLine();
1849 this->write(fallthroughVar);
1850 this->write(" = 1;");
1851 this->writeLine();
1852
1853 fIndentation--;
1854 this->writeLine("}");
1855 } else {
1856 // This is the default case. Since it's always last, we can just dump in the code.
1857 this->writeStatement(*c.statement());
1858 this->finishLine();
1859 }
1860 }
1861
1862 fIndentation--;
1863 this->writeLine("}");
1864 return;
1865 }
1866
1867 this->write("switch (");
1868 this->writeExpression(*s.value(), Precedence::kExpression);
1869 this->writeLine(") {");
1870 fIndentation++;
1871 // If a switch contains only a `default` case and nothing else, this confuses some drivers and
1872 // can lead to a crash. Adding a real case before the default seems to work around the bug,
1873 // and doesn't change the meaning of the switch. (skia:12465)
1874 if (s.cases().size() == 1 && s.cases().front()->as<SwitchCase>().isDefault()) {
1875 this->writeLine("case 0:");
1876 }
1877
1878 // The GLSL spec insists that the last case in a switch statement must have an associated
1879 // statement. In practice, the Apple GLSL compiler crashes if that statement is a no-op, such as
1880 // a semicolon or an empty brace pair. (This is filed as FB11992149.) It also crashes if we put
1881 // two `break` statements in a row. To work around this while honoring the rules of the
1882 // standard, we inject an extra break if and only if the last switch-case block is empty.
1883 bool foundEmptyCase = false;
1884
1885 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1886 const SwitchCase& c = stmt->as<SwitchCase>();
1887 if (c.isDefault()) {
1888 this->writeLine("default:");
1889 } else {
1890 this->write("case ");
1891 this->write(std::to_string(c.value()));
1892 this->writeLine(":");
1893 }
1894 if (c.statement()->isEmpty()) {
1895 foundEmptyCase = true;
1896 } else {
1897 foundEmptyCase = false;
1898 fIndentation++;
1899 this->writeStatement(*c.statement());
1900 this->finishLine();
1901 fIndentation--;
1902 }
1903 }
1904 if (foundEmptyCase) {
1905 fIndentation++;
1906 this->writeLine("break;");
1907 fIndentation--;
1908 }
1909 fIndentation--;
1910 this->finishLine();
1911 this->write("}");
1912 }
1913
writeReturnStatement(const ReturnStatement & r)1914 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1915 SkASSERT(fCurrentFunction);
1916
1917 this->write("return");
1918 if (r.expression()) {
1919 this->write(" ");
1920 this->writeExpression(*r.expression(), Precedence::kExpression);
1921 } else if (this->shouldRewriteVoidTypedFunctions(fCurrentFunction)) {
1922 // We need to rewrite `return` statements to say `return 0.0` since we are converting
1923 // void-typed functions to return floats instead.
1924 this->write(" 0.0");
1925 }
1926 this->write(";");
1927 }
1928
writeHeader()1929 void GLSLCodeGenerator::writeHeader() {
1930 if (fCaps.fVersionDeclString) {
1931 this->write(fCaps.fVersionDeclString);
1932 this->finishLine();
1933 }
1934 }
1935
writeProgramElement(const ProgramElement & e)1936 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1937 switch (e.kind()) {
1938 case ProgramElement::Kind::kExtension:
1939 this->writeExtension(e.as<Extension>().name());
1940 break;
1941
1942 case ProgramElement::Kind::kGlobalVar:
1943 this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
1944 break;
1945
1946 case ProgramElement::Kind::kInterfaceBlock:
1947 this->writeInterfaceBlock(e.as<InterfaceBlock>());
1948 break;
1949
1950 case ProgramElement::Kind::kFunction:
1951 this->writeFunction(e.as<FunctionDefinition>());
1952 break;
1953
1954 case ProgramElement::Kind::kFunctionPrototype:
1955 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1956 break;
1957
1958 case ProgramElement::Kind::kModifiers: {
1959 const ModifiersDeclaration& d = e.as<ModifiersDeclaration>();
1960 this->writeModifiers(d.layout(), d.modifierFlags(), /*globalContext=*/true);
1961 this->writeLine(";");
1962 break;
1963 }
1964 case ProgramElement::Kind::kStructDefinition:
1965 this->writeStructDefinition(e.as<StructDefinition>());
1966 break;
1967
1968 default:
1969 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1970 break;
1971 }
1972 }
1973
writeInputVars()1974 void GLSLCodeGenerator::writeInputVars() {
1975 // If we are using sk_FragCoordWorkaround, we don't need to apply RTFlip to gl_FragCoord.
1976 uint8_t useRTFlipUniform = fProgram.fInterface.fRTFlipUniform;
1977 if (!fCaps.fCanUseFragCoord) {
1978 useRTFlipUniform &= ~Program::Interface::kRTFlip_FragCoord;
1979 }
1980
1981 if (useRTFlipUniform != Program::Interface::kRTFlip_None) {
1982 const char* precision = this->usesPrecisionModifiers() ? "highp " : "";
1983 fGlobals.writeText("uniform ");
1984 fGlobals.writeText(precision);
1985 fGlobals.writeText("vec2 " SKSL_RTFLIP_NAME ";\n");
1986 }
1987 }
1988
generateCode()1989 bool GLSLCodeGenerator::generateCode() {
1990 this->writeHeader();
1991 OutputStream* rawOut = fOut;
1992 StringStream body;
1993 fOut = &body;
1994 // Write all the program elements except for functions.
1995 for (const ProgramElement* e : fProgram.elements()) {
1996 if (!e->is<FunctionDefinition>()) {
1997 this->writeProgramElement(*e);
1998 }
1999 }
2000 // Emit prototypes for every built-in function; these aren't always added in perfect order.
2001 for (const ProgramElement* e : fProgram.fSharedElements) {
2002 if (e->is<FunctionDefinition>()) {
2003 this->writeFunctionDeclaration(e->as<FunctionDefinition>().declaration());
2004 this->writeLine(";");
2005 }
2006 }
2007 // Write the functions last.
2008 // Why don't we write things in their original order? Because the Inliner likes to move function
2009 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
2010 // that the code relies on.
2011 for (const ProgramElement* e : fProgram.elements()) {
2012 if (e->is<FunctionDefinition>()) {
2013 this->writeProgramElement(*e);
2014 }
2015 }
2016 fOut = rawOut;
2017
2018 write_stringstream(fExtensions, *rawOut);
2019 this->writeInputVars();
2020 write_stringstream(fGlobals, *rawOut);
2021
2022 if (!fCaps.fCanUseFragCoord) {
2023 Layout layout;
2024 if (ProgramConfig::IsVertex(fProgram.fConfig->fKind)) {
2025 this->writeModifiers(layout, ModifierFlag::kOut, /*globalContext=*/true);
2026 if (this->usesPrecisionModifiers()) {
2027 this->write("highp ");
2028 }
2029 this->write("vec4 sk_FragCoord_Workaround;\n");
2030 } else if (ProgramConfig::IsFragment(fProgram.fConfig->fKind)) {
2031 this->writeModifiers(layout, ModifierFlag::kIn, /*globalContext=*/true);
2032 if (this->usesPrecisionModifiers()) {
2033 this->write("highp ");
2034 }
2035 this->write("vec4 sk_FragCoord_Workaround;\n");
2036 }
2037 }
2038
2039 if (this->usesPrecisionModifiers()) {
2040 const char* precision =
2041 fProgram.fConfig->fSettings.fForceHighPrecision ? "highp" : "mediump";
2042 this->write(String::printf("precision %s float;\n", precision));
2043 this->write(String::printf("precision %s sampler2D;\n", precision));
2044 if (fFoundExternalSamplerDecl && !fCaps.fNoDefaultPrecisionForExternalSamplers) {
2045 this->write(String::printf("precision %s samplerExternalOES;\n", precision));
2046 }
2047 if (fFoundRectSamplerDecl) {
2048 this->write(String::printf("precision %s sampler2DRect;\n", precision));
2049 }
2050 }
2051 write_stringstream(fExtraFunctions, *rawOut);
2052 write_stringstream(body, *rawOut);
2053 return fContext.fErrors->errorCount() == 0;
2054 }
2055
ToGLSL(Program & program,const ShaderCaps * caps,OutputStream & out,PrettyPrint pp)2056 bool ToGLSL(Program& program, const ShaderCaps* caps, OutputStream& out, PrettyPrint pp) {
2057 TRACE_EVENT0("skia.shaders", "SkSL::ToGLSL");
2058 SkASSERT(caps != nullptr);
2059
2060 program.fContext->fErrors->setSource(*program.fSource);
2061 GLSLCodeGenerator cg(program.fContext.get(), caps, &program, &out, pp);
2062 bool result = cg.generateCode();
2063 program.fContext->fErrors->setSource(std::string_view());
2064
2065 return result;
2066 }
2067
ToGLSL(Program & program,const ShaderCaps * caps,OutputStream & out)2068 bool ToGLSL(Program& program, const ShaderCaps* caps, OutputStream& out) {
2069 #if defined(SK_DEBUG)
2070 constexpr PrettyPrint defaultPrintOpts = PrettyPrint::kYes;
2071 #else
2072 constexpr PrettyPrint defaultPrintOpts = PrettyPrint::kNo;
2073 #endif
2074 return ToGLSL(program, caps, out, defaultPrintOpts);
2075 }
2076
ToGLSL(Program & program,const ShaderCaps * caps,std::string * out)2077 bool ToGLSL(Program& program, const ShaderCaps* caps, std::string* out) {
2078 StringStream buffer;
2079 if (!ToGLSL(program, caps, buffer)) {
2080 return false;
2081 }
2082 *out = buffer.str();
2083 return true;
2084 }
2085
2086 } // namespace SkSL
2087