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