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