Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes | List of all members
SkSL::GLSLCodeGenerator Class Referencefinal
Inheritance diagram for SkSL::GLSLCodeGenerator:
SkSL::CodeGenerator

Public Member Functions

 GLSLCodeGenerator (const Context *context, const ShaderCaps *caps, const Program *program, OutputStream *out)
 
bool generateCode () override
 
- Public Member Functions inherited from SkSL::CodeGenerator
 CodeGenerator (const Context *context, const ShaderCaps *caps, const Program *program, OutputStream *stream)
 
virtual ~CodeGenerator ()=default
 
OutputStreamoutputStream ()
 
void setOutputStream (OutputStream *output)
 

Protected Types

using Precedence = OperatorPrecedence
 
using INHERITED = CodeGenerator
 

Protected Member Functions

void write (std::string_view s)
 
void writeLine (std::string_view s=std::string_view())
 
void finishLine ()
 
void writeHeader ()
 
bool usesPrecisionModifiers () const
 
void writeIdentifier (std::string_view identifier)
 
std::string getTypeName (const Type &type)
 
void writeStructDefinition (const StructDefinition &s)
 
void writeType (const Type &type)
 
void writeExtension (std::string_view name, bool require=true)
 
void writeInterfaceBlock (const InterfaceBlock &intf)
 
void writeFunctionDeclaration (const FunctionDeclaration &f)
 
void writeFunctionPrototype (const FunctionPrototype &f)
 
void writeFunction (const FunctionDefinition &f)
 
void writeLayout (const Layout &layout)
 
void writeModifiers (const Layout &layout, ModifierFlags flags, bool globalContext)
 
void writeInputVars ()
 
void writeVarInitializer (const Variable &var, const Expression &value)
 
const char * getTypePrecision (const Type &type)
 
void writeTypePrecision (const Type &type)
 
void writeGlobalVarDeclaration (const GlobalVarDeclaration &e)
 
void writeVarDeclaration (const VarDeclaration &var, bool global)
 
void writeFragCoord ()
 
void writeVariableReference (const VariableReference &ref)
 
void writeExpression (const Expression &expr, Precedence parentPrecedence)
 
void writeIntrinsicCall (const FunctionCall &c)
 
void writeMinAbsHack (Expression &absExpr, Expression &otherExpr)
 
void writeDeterminantHack (const Expression &mat)
 
void writeInverseHack (const Expression &mat)
 
void writeTransposeHack (const Expression &mat)
 
void writeInverseSqrtHack (const Expression &x)
 
void writeMatrixComparisonWorkaround (const BinaryExpression &x)
 
void writeFunctionCall (const FunctionCall &c)
 
void writeConstructorCompound (const ConstructorCompound &c, Precedence parentPrecedence)
 
void writeConstructorDiagonalMatrix (const ConstructorDiagonalMatrix &c, Precedence parentPrecedence)
 
void writeAnyConstructor (const AnyConstructor &c, Precedence parentPrecedence)
 
void writeCastConstructor (const AnyConstructor &c, Precedence parentPrecedence)
 
void writeFieldAccess (const FieldAccess &f)
 
void writeSwizzle (const Swizzle &swizzle)
 
void writeBinaryExpression (const BinaryExpression &b, Precedence parentPrecedence)
 
void writeShortCircuitWorkaroundExpression (const BinaryExpression &b, Precedence parentPrecedence)
 
void writeTernaryExpression (const TernaryExpression &t, Precedence parentPrecedence)
 
void writeIndexExpression (const IndexExpression &expr)
 
void writePrefixExpression (const PrefixExpression &p, Precedence parentPrecedence)
 
void writePostfixExpression (const PostfixExpression &p, Precedence parentPrecedence)
 
void writeLiteral (const Literal &l)
 
void writeStatement (const Statement &s)
 
void writeBlock (const Block &b)
 
void writeIfStatement (const IfStatement &stmt)
 
void writeForStatement (const ForStatement &f)
 
void writeDoStatement (const DoStatement &d)
 
void writeExpressionStatement (const ExpressionStatement &s)
 
void writeSwitchStatement (const SwitchStatement &s)
 
void writeReturnStatement (const ReturnStatement &r)
 
void writeProgramElement (const ProgramElement &e)
 
bool shouldRewriteVoidTypedFunctions (const FunctionDeclaration *func) const
 

Protected Attributes

StringStream fExtensions
 
StringStream fGlobals
 
StringStream fExtraFunctions
 
std::string fFunctionHeader
 
int fVarCount = 0
 
int fIndentation = 0
 
bool fAtLineStart = false
 
const FunctionDeclarationfCurrentFunction = nullptr
 
bool fFoundDerivatives = false
 
bool fFoundExternalSamplerDecl = false
 
bool fFoundRectSamplerDecl = false
 
bool fSetupClockwise = false
 
bool fSetupFragPosition = false
 
bool fSetupFragCoordWorkaround = false
 
bool fWrittenAbsEmulation = false
 
bool fWrittenDeterminant2 = false
 
bool fWrittenDeterminant3 = false
 
bool fWrittenDeterminant4 = false
 
bool fWrittenInverse2 = false
 
bool fWrittenInverse3 = false
 
bool fWrittenInverse4 = false
 
bool fWrittenTranspose [3][3] = {}
 
- Protected Attributes inherited from SkSL::CodeGenerator
const ProgramfProgram
 
Context fContext
 
const ShaderCapsfCaps
 
OutputStreamfOut
 

Additional Inherited Members

- Static Protected Attributes inherited from SkSL::CodeGenerator
static constexpr float kSharpenTexturesBias = -.475f
 

Detailed Description

Definition at line 82 of file SkSLGLSLCodeGenerator.cpp.

Member Typedef Documentation

◆ INHERITED

Definition at line 232 of file SkSLGLSLCodeGenerator.cpp.

◆ Precedence

Definition at line 93 of file SkSLGLSLCodeGenerator.cpp.

Constructor & Destructor Documentation

◆ GLSLCodeGenerator()

SkSL::GLSLCodeGenerator::GLSLCodeGenerator ( const Context context,
const ShaderCaps caps,
const Program program,
OutputStream out 
)
inline

Definition at line 84 of file SkSLGLSLCodeGenerator.cpp.

88 : INHERITED(context, caps, program, out) {}

Member Function Documentation

◆ finishLine()

void SkSL::GLSLCodeGenerator::finishLine ( )
protected

Definition at line 256 of file SkSLGLSLCodeGenerator.cpp.

256 {
257 if (!fAtLineStart) {
258 this->writeLine();
259 }
260}
void writeLine(std::string_view s=std::string_view())

◆ generateCode()

bool SkSL::GLSLCodeGenerator::generateCode ( )
overridevirtual

Implements SkSL::CodeGenerator.

Definition at line 1956 of file SkSLGLSLCodeGenerator.cpp.

1956 {
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>()) {
1970 this->writeFunctionDeclaration(e->as<FunctionDefinition>().declaration());
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}
const ShaderCaps & fCaps
const Program & fProgram
ErrorReporter * fErrors
Definition SkSLContext.h:36
void writeModifiers(const Layout &layout, ModifierFlags flags, bool globalContext)
void writeProgramElement(const ProgramElement &e)
void write(std::string_view s)
void writeFunctionDeclaration(const FunctionDeclaration &f)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
void write_stringstream(const StringStream &s, OutputStream &out)
Definition SkSLUtil.cpp:41
static bool IsVertex(ProgramKind kind)
static bool IsFragment(ProgramKind kind)
std::unique_ptr< ProgramConfig > fConfig
bool fCanUseFragCoord
Definition SkSLUtil.h:125
bool fNoDefaultPrecisionForExternalSamplers
Definition SkSLUtil.h:137

◆ getTypeName()

std::string SkSL::GLSLCodeGenerator::getTypeName ( const Type type)
protected

Definition at line 289 of file SkSLGLSLCodeGenerator.cpp.

289 {
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}
#define SK_ABORT(message,...)
Definition SkAssert.h:70
const std::unique_ptr< Type > fUShort
const std::unique_ptr< Type > fShort
const std::unique_ptr< Type > fBool
const std::unique_ptr< Type > fFloat
const std::unique_ptr< Type > fHalf
const BuiltinTypes & fTypes
Definition SkSLContext.h:30
std::string getTypeName(const Type &type)
GAsyncResult * result

◆ getTypePrecision()

const char * SkSL::GLSLCodeGenerator::getTypePrecision ( const Type type)
protected

Definition at line 1494 of file SkSLGLSLCodeGenerator.cpp.

1494 {
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}
const std::unique_ptr< Type > fInt
const std::unique_ptr< Type > fUInt
const char * getTypePrecision(const Type &type)

◆ shouldRewriteVoidTypedFunctions()

bool SkSL::GLSLCodeGenerator::shouldRewriteVoidTypedFunctions ( const FunctionDeclaration func) const
protected

Definition at line 1309 of file SkSLGLSLCodeGenerator.cpp.

1309 {
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}
bool fCanUseVoidInSequenceExpressions
Definition SkSLUtil.h:110

◆ usesPrecisionModifiers()

bool SkSL::GLSLCodeGenerator::usesPrecisionModifiers ( ) const
protected

Definition at line 268 of file SkSLGLSLCodeGenerator.cpp.

268 {
270}
bool fUsesPrecisionModifiers
Definition SkSLUtil.h:95

◆ write()

void SkSL::GLSLCodeGenerator::write ( std::string_view  s)
protected

Definition at line 235 of file SkSLGLSLCodeGenerator.cpp.

235 {
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}
virtual void write(const void *s, size_t size)=0
virtual void writeText(const char *s)=0
struct MyStruct s

◆ writeAnyConstructor()

void SkSL::GLSLCodeGenerator::writeAnyConstructor ( const AnyConstructor c,
Precedence  parentPrecedence 
)
protected

Definition at line 1001 of file SkSLGLSLCodeGenerator.cpp.

1001 {
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}
void writeExpression(const Expression &expr, Precedence parentPrecedence)
void writeType(const Type &type)
std::string void void auto Separator()
Definition SkSLString.h:30

◆ writeBinaryExpression()

void SkSL::GLSLCodeGenerator::writeBinaryExpression ( const BinaryExpression b,
Precedence  parentPrecedence 
)
protected

Definition at line 1175 of file SkSLGLSLCodeGenerator.cpp.

1176 {
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}
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
void writeShortCircuitWorkaroundExpression(const BinaryExpression &b, Precedence parentPrecedence)
void writeMatrixComparisonWorkaround(const BinaryExpression &x)
static bool b
bool ContainsRTAdjust(const Expression &expr)
bool is_sk_position(const Expression &expr)
bool is_sk_samplemask(const Expression &expr)
bool fRewriteMatrixComparisons
Definition SkSLUtil.h:142
bool fUnfoldShortCircuitAsTernary
Definition SkSLUtil.h:130

◆ writeBlock()

void SkSL::GLSLCodeGenerator::writeBlock ( const Block b)
protected

Definition at line 1642 of file SkSLGLSLCodeGenerator.cpp.

1642 {
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}
void writeStatement(const Statement &s)

◆ writeCastConstructor()

void SkSL::GLSLCodeGenerator::writeCastConstructor ( const AnyConstructor c,
Precedence  parentPrecedence 
)
protected

Definition at line 983 of file SkSLGLSLCodeGenerator.cpp.

983 {
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}
#define SkASSERT(cond)
Definition SkAssert.h:116
const std::unique_ptr< Type > fFloatLiteral
void writeAnyConstructor(const AnyConstructor &c, Precedence parentPrecedence)

◆ writeConstructorCompound()

void SkSL::GLSLCodeGenerator::writeConstructorCompound ( const ConstructorCompound c,
Precedence  parentPrecedence 
)
protected

Definition at line 946 of file SkSLGLSLCodeGenerator.cpp.

947 {
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}
bool IsTrivialExpression(const Expression &expr)

◆ writeConstructorDiagonalMatrix()

void SkSL::GLSLCodeGenerator::writeConstructorDiagonalMatrix ( const ConstructorDiagonalMatrix c,
Precedence  parentPrecedence 
)
protected

Definition at line 928 of file SkSLGLSLCodeGenerator.cpp.

929 {
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}

◆ writeDeterminantHack()

void SkSL::GLSLCodeGenerator::writeDeterminantHack ( const Expression mat)
protected

Definition at line 516 of file SkSLGLSLCodeGenerator.cpp.

516 {
517 const Type& type = mat.type();
518 if (type.matches(*fContext.fTypes.fFloat2x2) ||
519 type.matches(*fContext.fTypes.fHalf2x2)) {
520 this->write("_determinant2(");
524 }
525 } else if (type.matches(*fContext.fTypes.fFloat3x3) ||
526 type.matches(*fContext.fTypes.fHalf3x3)) {
527 this->write("_determinant3(");
531 }
532 } else if (type.matches(*fContext.fTypes.fFloat4x4) ||
533 type.matches(*fContext.fTypes.fHalf4x4)) {
534 this->write("_determinant4(");
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}
#define SkDEBUGFAILF(fmt,...)
Definition SkAssert.h:119
const std::unique_ptr< Type > fHalf2x2
const std::unique_ptr< Type > fFloat2x2
const std::unique_ptr< Type > fFloat4x4
const std::unique_ptr< Type > fHalf3x3
const std::unique_ptr< Type > fFloat3x3
const std::unique_ptr< Type > fHalf4x4
void writeText(const char *s) override
static constexpr char kDeterminant4[]
static constexpr char kDeterminant2[]
static constexpr char kDeterminant3[]

◆ writeDoStatement()

void SkSL::GLSLCodeGenerator::writeDoStatement ( const DoStatement d)
protected

Definition at line 1708 of file SkSLGLSLCodeGenerator.cpp.

1708 {
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}
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
bool fRewriteDoWhileLoops
Definition SkSLUtil.h:132

◆ writeExpression()

void SkSL::GLSLCodeGenerator::writeExpression ( const Expression expr,
Precedence  parentPrecedence 
)
protected

Definition at line 382 of file SkSLGLSLCodeGenerator.cpp.

382 {
383 switch (expr.kind()) {
384 case Expression::Kind::kBinary:
385 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
386 break;
387 case Expression::Kind::kConstructorDiagonalMatrix:
388 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
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:
432 this->writeVariableReference(expr.as<VariableReference>());
433 break;
434 case Expression::Kind::kTernary:
435 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
436 break;
437 case Expression::Kind::kIndex:
438 this->writeIndexExpression(expr.as<IndexExpression>());
439 break;
440 default:
441 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
442 break;
443 }
444}
void writePrefixExpression(const PrefixExpression &p, Precedence parentPrecedence)
void writeFieldAccess(const FieldAccess &f)
void writeIndexExpression(const IndexExpression &expr)
void writeTernaryExpression(const TernaryExpression &t, Precedence parentPrecedence)
void writeCastConstructor(const AnyConstructor &c, Precedence parentPrecedence)
void writeBinaryExpression(const BinaryExpression &b, Precedence parentPrecedence)
void writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix &c, Precedence parentPrecedence)
void writeFunctionCall(const FunctionCall &c)
void writeSwizzle(const Swizzle &swizzle)
void writeLiteral(const Literal &l)
void writeVariableReference(const VariableReference &ref)
void writeConstructorCompound(const ConstructorCompound &c, Precedence parentPrecedence)
void writePostfixExpression(const PostfixExpression &p, Precedence parentPrecedence)

◆ writeExpressionStatement()

void SkSL::GLSLCodeGenerator::writeExpressionStatement ( const ExpressionStatement s)
protected

Definition at line 1761 of file SkSLGLSLCodeGenerator.cpp.

1761 {
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}
bool HasSideEffects(const Expression &expr)

◆ writeExtension()

void SkSL::GLSLCodeGenerator::writeExtension ( std::string_view  name,
bool  require = true 
)
protected

Definition at line 262 of file SkSLGLSLCodeGenerator.cpp.

262 {
263 fExtensions.writeText("#extension ");
264 fExtensions.write(name.data(), name.length());
265 fExtensions.writeText(require ? " : require\n" : " : enable\n");
266}
void write(const void *s, size_t size) override
const char * name
Definition fuchsia.cc:50

◆ writeFieldAccess()

void SkSL::GLSLCodeGenerator::writeFieldAccess ( const FieldAccess f)
protected

Definition at line 1128 of file SkSLGLSLCodeGenerator.cpp.

1128 {
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}
constexpr int SK_POSITION_BUILTIN
constexpr int SK_POINTSIZE_BUILTIN
void writeIdentifier(std::string_view identifier)

◆ writeForStatement()

void SkSL::GLSLCodeGenerator::writeForStatement ( const ForStatement f)
protected

Definition at line 1673 of file SkSLGLSLCodeGenerator.cpp.

1673 {
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}
static std::unique_ptr< Literal > MakeBool(const Context &context, Position pos, bool value)
Definition SkSLLiteral.h:69
bool fAddAndTrueToLoopCondition
Definition SkSLUtil.h:127

◆ writeFragCoord()

void SkSL::GLSLCodeGenerator::writeFragCoord ( )
protected

Definition at line 1012 of file SkSLGLSLCodeGenerator.cpp.

1012 {
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}
#define SKSL_RTFLIP_NAME
Definition SkSLProgram.h:19

◆ writeFunction()

void SkSL::GLSLCodeGenerator::writeFunction ( const FunctionDefinition f)
protected

Definition at line 1370 of file SkSLGLSLCodeGenerator.cpp.

1370 {
1371 fSetupFragPosition = false;
1373 fSetupClockwise = false;
1374 fCurrentFunction = &f.declaration();
1375
1376 this->writeFunctionDeclaration(f.declaration());
1377 this->writeLine(" {");
1378 fIndentation++;
1379
1380 fFunctionHeader.clear();
1381 OutputStream* oldOut = fOut;
1382 StringStream buffer;
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
1391 if (this->shouldRewriteVoidTypedFunctions(&f.declaration())) {
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}
const FunctionDeclaration * fCurrentFunction
bool shouldRewriteVoidTypedFunctions(const FunctionDeclaration *func) const
static const uint8_t buffer[]

◆ writeFunctionCall()

void SkSL::GLSLCodeGenerator::writeFunctionCall ( const FunctionCall c)
protected

Definition at line 671 of file SkSLGLSLCodeGenerator.cpp.

671 {
672 const FunctionDeclaration& function = c.function();
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 {
834 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat2));
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 {
846 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat3));
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 {
856 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat4));
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}
const std::unique_ptr< Type > fFloat2
const std::unique_ptr< Type > fFloat4
const std::unique_ptr< Type > fSamplerExternalOES
const std::unique_ptr< Type > fFloat3
static constexpr float kSharpenTexturesBias
void writeInverseSqrtHack(const Expression &x)
void writeInverseHack(const Expression &mat)
void writeTransposeHack(const Expression &mat)
void writeMinAbsHack(Expression &absExpr, Expression &otherExpr)
void writeDeterminantHack(const Expression &mat)
void writeExtension(std::string_view name, bool require=true)
Dart_NativeFunction function
Definition fuchsia.cc:51
static bool is_abs(Expression &expr)
@ 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
const char * shaderDerivativeExtensionString() const
Definition SkSLUtil.h:50
bool fMustForceNegatedAtanParamToFloat
Definition SkSLUtil.h:113
bool fEmulateAbsIntFunction
Definition SkSLUtil.h:131
bool fRemovePowWithConstantExponent
Definition SkSLUtil.h:134
bool fBuiltinFMASupport
Definition SkSLUtil.h:106
bool fBuiltinDeterminantSupport
Definition SkSLUtil.h:107
bool fMustForceNegatedLdexpParamToMultiply
Definition SkSLUtil.h:114
bool fCanUseFractForNegativeValues
Definition SkSLUtil.h:112
bool fCanUseMinAndAbsTogether
Definition SkSLUtil.h:111
SkSL::GLSLGeneration fGLSLGeneration
Definition SkSLUtil.h:82

◆ writeFunctionDeclaration()

void SkSL::GLSLCodeGenerator::writeFunctionDeclaration ( const FunctionDeclaration f)
protected

Definition at line 1318 of file SkSLGLSLCodeGenerator.cpp.

1318 {
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());
1340 ModifierFlags flags = param->modifierFlags();
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}
void writeTypePrecision(const Type &type)
FlutterSemanticsFlag flags
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
bool fRemoveConstFromFunctionParameters
Definition SkSLUtil.h:144

◆ writeFunctionPrototype()

void SkSL::GLSLCodeGenerator::writeFunctionPrototype ( const FunctionPrototype f)
protected

Definition at line 1407 of file SkSLGLSLCodeGenerator.cpp.

1407 {
1408 this->writeFunctionDeclaration(f.declaration());
1409 this->writeLine(";");
1410}

◆ writeGlobalVarDeclaration()

void SkSL::GLSLCodeGenerator::writeGlobalVarDeclaration ( const GlobalVarDeclaration e)
protected

Definition at line 1524 of file SkSLGLSLCodeGenerator.cpp.

1524 {
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}
constexpr int SK_FRAGCOLOR_BUILTIN
void writeVarDeclaration(const VarDeclaration &var, bool global)
bool mustDeclareFragmentShaderOutput() const
Definition SkSLUtil.h:43

◆ writeHeader()

void SkSL::GLSLCodeGenerator::writeHeader ( )
protected

Definition at line 1896 of file SkSLGLSLCodeGenerator.cpp.

1896 {
1899 this->finishLine();
1900 }
1901}
const char * fVersionDeclString
Definition SkSLUtil.h:153

◆ writeIdentifier()

void SkSL::GLSLCodeGenerator::writeIdentifier ( std::string_view  identifier)
protected

Definition at line 272 of file SkSLGLSLCodeGenerator.cpp.

272 {
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}
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
constexpr bool contains(std::string_view str, std::string_view needle)

◆ writeIfStatement()

void SkSL::GLSLCodeGenerator::writeIfStatement ( const IfStatement stmt)
protected

Definition at line 1662 of file SkSLGLSLCodeGenerator.cpp.

1662 {
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}

◆ writeIndexExpression()

void SkSL::GLSLCodeGenerator::writeIndexExpression ( const IndexExpression expr)
protected

Definition at line 1105 of file SkSLGLSLCodeGenerator.cpp.

1105 {
1106 this->writeExpression(*expr.base(), Precedence::kPostfix);
1107 this->write("[");
1108 this->writeExpression(*expr.index(), Precedence::kExpression);
1109 this->write("]");
1110}

◆ writeInputVars()

void SkSL::GLSLCodeGenerator::writeInputVars ( )
protected

Definition at line 1941 of file SkSLGLSLCodeGenerator.cpp.

1941 {
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}
ProgramInterface fInterface

◆ writeInterfaceBlock()

void SkSL::GLSLCodeGenerator::writeInterfaceBlock ( const InterfaceBlock intf)
protected

Definition at line 1459 of file SkSLGLSLCodeGenerator.cpp.

1459 {
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}

◆ writeIntrinsicCall()

void SkSL::GLSLCodeGenerator::writeIntrinsicCall ( const FunctionCall c)
protected

◆ writeInverseHack()

void SkSL::GLSLCodeGenerator::writeInverseHack ( const Expression mat)
protected

Definition at line 610 of file SkSLGLSLCodeGenerator.cpp.

610 {
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;
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;
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;
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}
static constexpr char kInverse4[]
static constexpr char kInverse3[]
static constexpr char kInverse2[]

◆ writeInverseSqrtHack()

void SkSL::GLSLCodeGenerator::writeInverseSqrtHack ( const Expression x)
protected

Definition at line 468 of file SkSLGLSLCodeGenerator.cpp.

468 {
469 this->write("(1.0 / sqrt(");
470 this->writeExpression(x, Precedence::kExpression);
471 this->write("))");
472}
double x

◆ writeLayout()

void SkSL::GLSLCodeGenerator::writeLayout ( const Layout layout)
protected

◆ writeLine()

void SkSL::GLSLCodeGenerator::writeLine ( std::string_view  s = std::string_view())
protected

Definition at line 250 of file SkSLGLSLCodeGenerator.cpp.

250 {
251 this->write(s);
252 fOut->writeText("\n");
253 fAtLineStart = true;
254}

◆ writeLiteral()

void SkSL::GLSLCodeGenerator::writeLiteral ( const Literal l)
protected

Definition at line 1294 of file SkSLGLSLCodeGenerator.cpp.

1294 {
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 }
1306 this->write(l.description(OperatorPrecedence::kExpression));
1307}

◆ writeMatrixComparisonWorkaround()

void SkSL::GLSLCodeGenerator::writeMatrixComparisonWorkaround ( const BinaryExpression x)
protected

Definition at line 1150 of file SkSLGLSLCodeGenerator.cpp.

1150 {
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}

◆ writeMinAbsHack()

void SkSL::GLSLCodeGenerator::writeMinAbsHack ( Expression absExpr,
Expression otherExpr 
)
protected

Definition at line 453 of file SkSLGLSLCodeGenerator.cpp.

453 {
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}

◆ writeModifiers()

void SkSL::GLSLCodeGenerator::writeModifiers ( const Layout layout,
ModifierFlags  flags,
bool  globalContext 
)
protected

Definition at line 1412 of file SkSLGLSLCodeGenerator.cpp.

1414 {
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 }
1422 this->write("noperspective ");
1423 }
1424
1425 if (flags.isConst()) {
1426 this->write("const ");
1427 }
1428 if (flags.isUniform()) {
1429 this->write("uniform ");
1430 }
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}

◆ writePostfixExpression()

void SkSL::GLSLCodeGenerator::writePostfixExpression ( const PostfixExpression p,
Precedence  parentPrecedence 
)
protected

Definition at line 1282 of file SkSLGLSLCodeGenerator.cpp.

1283 {
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}

◆ writePrefixExpression()

void SkSL::GLSLCodeGenerator::writePrefixExpression ( const PrefixExpression p,
Precedence  parentPrecedence 
)
protected

Definition at line 1270 of file SkSLGLSLCodeGenerator.cpp.

1271 {
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}

◆ writeProgramElement()

void SkSL::GLSLCodeGenerator::writeProgramElement ( const ProgramElement e)
protected

Definition at line 1903 of file SkSLGLSLCodeGenerator.cpp.

1903 {
1904 switch (e.kind()) {
1905 case ProgramElement::Kind::kExtension:
1906 this->writeExtension(e.as<Extension>().name());
1907 break;
1908
1909 case ProgramElement::Kind::kGlobalVar:
1910 this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
1911 break;
1912
1913 case ProgramElement::Kind::kInterfaceBlock:
1914 this->writeInterfaceBlock(e.as<InterfaceBlock>());
1915 break;
1916
1917 case ProgramElement::Kind::kFunction:
1918 this->writeFunction(e.as<FunctionDefinition>());
1919 break;
1920
1921 case ProgramElement::Kind::kFunctionPrototype:
1922 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1923 break;
1924
1925 case ProgramElement::Kind::kModifiers: {
1926 const ModifiersDeclaration& d = e.as<ModifiersDeclaration>();
1927 this->writeModifiers(d.layout(), d.modifierFlags(), /*globalContext=*/true);
1928 this->writeLine(";");
1929 break;
1930 }
1931 case ProgramElement::Kind::kStructDefinition:
1932 this->writeStructDefinition(e.as<StructDefinition>());
1933 break;
1934
1935 default:
1936 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1937 break;
1938 }
1939}
void writeFunctionPrototype(const FunctionPrototype &f)
void writeStructDefinition(const StructDefinition &s)
void writeFunction(const FunctionDefinition &f)
void writeGlobalVarDeclaration(const GlobalVarDeclaration &e)
void writeInterfaceBlock(const InterfaceBlock &intf)

◆ writeReturnStatement()

void SkSL::GLSLCodeGenerator::writeReturnStatement ( const ReturnStatement r)
protected

Definition at line 1881 of file SkSLGLSLCodeGenerator.cpp.

1881 {
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}

◆ writeShortCircuitWorkaroundExpression()

void SkSL::GLSLCodeGenerator::writeShortCircuitWorkaroundExpression ( const BinaryExpression b,
Precedence  parentPrecedence 
)
protected

Definition at line 1226 of file SkSLGLSLCodeGenerator.cpp.

1227 {
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}

◆ writeStatement()

void SkSL::GLSLCodeGenerator::writeStatement ( const Statement s)
protected

Definition at line 1598 of file SkSLGLSLCodeGenerator.cpp.

1598 {
1599 switch (s.kind()) {
1600 case Statement::Kind::kBlock:
1601 this->writeBlock(s.as<Block>());
1602 break;
1603 case Statement::Kind::kExpression:
1604 this->writeExpressionStatement(s.as<ExpressionStatement>());
1605 break;
1606 case Statement::Kind::kReturn:
1607 this->writeReturnStatement(s.as<ReturnStatement>());
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:
1622 this->writeSwitchStatement(s.as<SwitchStatement>());
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}
void writeForStatement(const ForStatement &f)
void writeExpressionStatement(const ExpressionStatement &s)
void writeReturnStatement(const ReturnStatement &r)
void writeSwitchStatement(const SwitchStatement &s)
void writeDoStatement(const DoStatement &d)
void writeIfStatement(const IfStatement &stmt)

◆ writeStructDefinition()

void SkSL::GLSLCodeGenerator::writeStructDefinition ( const StructDefinition s)
protected

Definition at line 356 of file SkSLGLSLCodeGenerator.cpp.

356 {
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}

◆ writeSwitchStatement()

void SkSL::GLSLCodeGenerator::writeSwitchStatement ( const SwitchStatement s)
protected

Definition at line 1770 of file SkSLGLSLCodeGenerator.cpp.

1770 {
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}
bool fRewriteSwitchStatements
Definition SkSLUtil.h:133

◆ writeSwizzle()

void SkSL::GLSLCodeGenerator::writeSwizzle ( const Swizzle swizzle)
protected

Definition at line 1144 of file SkSLGLSLCodeGenerator.cpp.

1144 {
1145 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
1146 this->write(".");
1147 this->write(Swizzle::MaskString(swizzle.components()));
1148}
static std::string MaskString(const ComponentArray &inComponents)

◆ writeTernaryExpression()

void SkSL::GLSLCodeGenerator::writeTernaryExpression ( const TernaryExpression t,
Precedence  parentPrecedence 
)
protected

Definition at line 1255 of file SkSLGLSLCodeGenerator.cpp.

1256 {
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}

◆ writeTransposeHack()

void SkSL::GLSLCodeGenerator::writeTransposeHack ( const Expression mat)
protected

Definition at line 640 of file SkSLGLSLCodeGenerator.cpp.

640 {
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}

◆ writeType()

void SkSL::GLSLCodeGenerator::writeType ( const Type type)
protected

Definition at line 378 of file SkSLGLSLCodeGenerator.cpp.

378 {
379 this->writeIdentifier(this->getTypeName(type));
380}

◆ writeTypePrecision()

void SkSL::GLSLCodeGenerator::writeTypePrecision ( const Type type)
protected

Definition at line 1520 of file SkSLGLSLCodeGenerator.cpp.

1520 {
1521 this->write(this->getTypePrecision(type));
1522}

◆ writeVarDeclaration()

void SkSL::GLSLCodeGenerator::writeVarDeclaration ( const VarDeclaration var,
bool  global 
)
protected

Definition at line 1552 of file SkSLGLSLCodeGenerator.cpp.

1552 {
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 ||
1558 decl.baseType().typeKind() == Type::TypeKind::kSeparateSampler ||
1559 decl.baseType().typeKind() == Type::TypeKind::kTexture) {
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 }
1579 var->type().matches(*fContext.fTypes.fSamplerExternalOES)) {
1581 fContext.fErrors->error(decl.position(), "external texture support is not enabled");
1582 } else {
1585 }
1588 }
1590 }
1591 }
1592 if (!fFoundRectSamplerDecl && var->type().matches(*fContext.fTypes.fSampler2DRect)) {
1593 fFoundRectSamplerDecl = true;
1594 }
1595 this->write(";");
1596}
const std::unique_ptr< Type > fSampler2DRect
void error(Position position, std::string_view msg)
void writeVarInitializer(const Variable &var, const Expression &value)
const char * secondExternalTextureExtensionString() const
Definition SkSLUtil.h:64
bool fExternalTextureSupport
Definition SkSLUtil.h:99
const char * externalTextureExtensionString() const
Definition SkSLUtil.h:59

◆ writeVariableReference()

void SkSL::GLSLCodeGenerator::writeVariableReference ( const VariableReference ref)
protected

Definition at line 1047 of file SkSLGLSLCodeGenerator.cpp.

1047 {
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}
constexpr int SK_SAMPLEMASK_BUILTIN
constexpr int SK_CLOCKWISE_BUILTIN
constexpr int SK_VERTEXID_BUILTIN
constexpr int SK_LASTFRAGCOLOR_BUILTIN
constexpr int SK_INSTANCEID_BUILTIN
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
constexpr int SK_FRAGCOORD_BUILTIN
constexpr int SK_SAMPLEMASKIN_BUILTIN
bool fDualSourceBlendingSupport
Definition SkSLUtil.h:84
const char * fFBFetchColorName
Definition SkSLUtil.h:158

◆ writeVarInitializer()

void SkSL::GLSLCodeGenerator::writeVarInitializer ( const Variable var,
const Expression value 
)
protected

Definition at line 1490 of file SkSLGLSLCodeGenerator.cpp.

1490 {
1491 this->writeExpression(value, Precedence::kExpression);
1492}

Member Data Documentation

◆ fAtLineStart

bool SkSL::GLSLCodeGenerator::fAtLineStart = false
protected

Definition at line 215 of file SkSLGLSLCodeGenerator.cpp.

◆ fCurrentFunction

const FunctionDeclaration* SkSL::GLSLCodeGenerator::fCurrentFunction = nullptr
protected

Definition at line 216 of file SkSLGLSLCodeGenerator.cpp.

◆ fExtensions

StringStream SkSL::GLSLCodeGenerator::fExtensions
protected

Definition at line 209 of file SkSLGLSLCodeGenerator.cpp.

◆ fExtraFunctions

StringStream SkSL::GLSLCodeGenerator::fExtraFunctions
protected

Definition at line 211 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundDerivatives

bool SkSL::GLSLCodeGenerator::fFoundDerivatives = false
protected

Definition at line 219 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundExternalSamplerDecl

bool SkSL::GLSLCodeGenerator::fFoundExternalSamplerDecl = false
protected

Definition at line 220 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundRectSamplerDecl

bool SkSL::GLSLCodeGenerator::fFoundRectSamplerDecl = false
protected

Definition at line 221 of file SkSLGLSLCodeGenerator.cpp.

◆ fFunctionHeader

std::string SkSL::GLSLCodeGenerator::fFunctionHeader
protected

Definition at line 212 of file SkSLGLSLCodeGenerator.cpp.

◆ fGlobals

StringStream SkSL::GLSLCodeGenerator::fGlobals
protected

Definition at line 210 of file SkSLGLSLCodeGenerator.cpp.

◆ fIndentation

int SkSL::GLSLCodeGenerator::fIndentation = 0
protected

Definition at line 214 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupClockwise

bool SkSL::GLSLCodeGenerator::fSetupClockwise = false
protected

Definition at line 222 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupFragCoordWorkaround

bool SkSL::GLSLCodeGenerator::fSetupFragCoordWorkaround = false
protected

Definition at line 224 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupFragPosition

bool SkSL::GLSLCodeGenerator::fSetupFragPosition = false
protected

Definition at line 223 of file SkSLGLSLCodeGenerator.cpp.

◆ fVarCount

int SkSL::GLSLCodeGenerator::fVarCount = 0
protected

Definition at line 213 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenAbsEmulation

bool SkSL::GLSLCodeGenerator::fWrittenAbsEmulation = false
protected

Definition at line 227 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant2

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant2 = false
protected

Definition at line 228 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant3

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant3 = false
protected

Definition at line 228 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant4

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant4 = false
protected

Definition at line 228 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse2

bool SkSL::GLSLCodeGenerator::fWrittenInverse2 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse3

bool SkSL::GLSLCodeGenerator::fWrittenInverse3 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse4

bool SkSL::GLSLCodeGenerator::fWrittenInverse4 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenTranspose

bool SkSL::GLSLCodeGenerator::fWrittenTranspose[3][3] = {}
protected

Definition at line 230 of file SkSLGLSLCodeGenerator.cpp.

230{};

The documentation for this class was generated from the following file: