Flutter Engine
The Flutter Engine
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
 
virtual bool generateCode ()=0
 
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 83 of file SkSLGLSLCodeGenerator.cpp.

Member Typedef Documentation

◆ INHERITED

Definition at line 233 of file SkSLGLSLCodeGenerator.cpp.

◆ Precedence

Definition at line 94 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 85 of file SkSLGLSLCodeGenerator.cpp.

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

Member Function Documentation

◆ finishLine()

void SkSL::GLSLCodeGenerator::finishLine ( )
protected

Definition at line 257 of file SkSLGLSLCodeGenerator.cpp.

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

◆ generateCode()

bool SkSL::GLSLCodeGenerator::generateCode ( )
overridevirtual

Implements SkSL::CodeGenerator.

Definition at line 1967 of file SkSLGLSLCodeGenerator.cpp.

1967 {
1968 this->writeHeader();
1969 OutputStream* rawOut = fOut;
1970 StringStream body;
1971 fOut = &body;
1972 // Write all the program elements except for functions.
1973 for (const ProgramElement* e : fProgram.elements()) {
1974 if (!e->is<FunctionDefinition>()) {
1975 this->writeProgramElement(*e);
1976 }
1977 }
1978 // Emit prototypes for every built-in function; these aren't always added in perfect order.
1979 for (const ProgramElement* e : fProgram.fSharedElements) {
1980 if (e->is<FunctionDefinition>()) {
1981 this->writeFunctionDeclaration(e->as<FunctionDefinition>().declaration());
1982 this->writeLine(";");
1983 }
1984 }
1985 // Write the functions last.
1986 // Why don't we write things in their original order? Because the Inliner likes to move function
1987 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
1988 // that the code relies on.
1989 for (const ProgramElement* e : fProgram.elements()) {
1990 if (e->is<FunctionDefinition>()) {
1991 this->writeProgramElement(*e);
1992 }
1993 }
1994 fOut = rawOut;
1995
1997 this->writeInputVars();
1998 write_stringstream(fGlobals, *rawOut);
1999
2000 if (!fCaps.fCanUseFragCoord) {
2001 Layout layout;
2003 this->writeModifiers(layout, ModifierFlag::kOut, /*globalContext=*/true);
2004 if (this->usesPrecisionModifiers()) {
2005 this->write("highp ");
2006 }
2007 this->write("vec4 sk_FragCoord_Workaround;\n");
2008 } else if (ProgramConfig::IsFragment(fProgram.fConfig->fKind)) {
2009 this->writeModifiers(layout, ModifierFlag::kIn, /*globalContext=*/true);
2010 if (this->usesPrecisionModifiers()) {
2011 this->write("highp ");
2012 }
2013 this->write("vec4 sk_FragCoord_Workaround;\n");
2014 }
2015 }
2016
2017 if (this->usesPrecisionModifiers()) {
2018 const char* precision =
2019 fProgram.fConfig->fSettings.fForceHighPrecision ? "highp" : "mediump";
2020 this->write(String::printf("precision %s float;\n", precision));
2021 this->write(String::printf("precision %s sampler2D;\n", precision));
2023 this->write(String::printf("precision %s samplerExternalOES;\n", precision));
2024 }
2026 this->write(String::printf("precision %s sampler2DRect;\n", precision));
2027 }
2028 }
2030 write_stringstream(body, *rawOut);
2031 return fContext.fErrors->errorCount() == 0;
2032}
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
Definition: SkSLString.cpp:83
void write_stringstream(const StringStream &s, OutputStream &out)
Definition: SkSLUtil.cpp:42
static bool IsVertex(ProgramKind kind)
static bool IsFragment(ProgramKind kind)
ElementsCollection elements() const
Definition: SkSLProgram.h:140
std::vector< const ProgramElement * > fSharedElements
Definition: SkSLProgram.h:164
std::unique_ptr< ProgramConfig > fConfig
Definition: SkSLProgram.h:153
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 290 of file SkSLGLSLCodeGenerator.cpp.

290 {
291 const Type& type = raw.resolve().scalarTypeForLiteral();
292 switch (type.typeKind()) {
294 const Type& component = type.componentType();
295 std::string result;
296 if (component.matches(*fContext.fTypes.fFloat) ||
297 component.matches(*fContext.fTypes.fHalf)) {
298 result = "vec";
299 }
300 else if (component.isSigned()) {
301 result = "ivec";
302 }
303 else if (component.isUnsigned()) {
304 result = "uvec";
305 }
306 else if (component.matches(*fContext.fTypes.fBool)) {
307 result = "bvec";
308 }
309 else {
310 SK_ABORT("unsupported vector type");
311 }
312 result += std::to_string(type.columns());
313 return result;
314 }
316 std::string result;
317 const Type& component = type.componentType();
318 if (component.matches(*fContext.fTypes.fFloat) ||
319 component.matches(*fContext.fTypes.fHalf)) {
320 result = "mat";
321 }
322 else {
323 SK_ABORT("unsupported matrix type");
324 }
325 result += std::to_string(type.columns());
326 if (type.columns() != type.rows()) {
327 result += "x";
328 result += std::to_string(type.rows());
329 }
330 return result;
331 }
333 std::string baseTypeName = this->getTypeName(type.componentType());
334 if (type.isUnsizedArray()) {
335 return String::printf("%s[]", baseTypeName.c_str());
336 }
337 return String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
338 }
340 if (type.matches(*fContext.fTypes.fHalf)) {
341 return "float";
342 }
343 else if (type.matches(*fContext.fTypes.fShort)) {
344 return "int";
345 }
346 else if (type.matches(*fContext.fTypes.fUShort)) {
347 return "uint";
348 }
349
350 return std::string(type.name());
351 }
352 default:
353 return std::string(type.name());
354 }
355}
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
GLenum type
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
static SkString to_string(int n)
Definition: nanobench.cpp:119

◆ getTypePrecision()

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

Definition at line 1505 of file SkSLGLSLCodeGenerator.cpp.

1505 {
1506 if (this->usesPrecisionModifiers()) {
1507 switch (type.typeKind()) {
1509 if (type.matches(*fContext.fTypes.fShort) ||
1510 type.matches(*fContext.fTypes.fUShort) ||
1511 type.matches(*fContext.fTypes.fHalf)) {
1512 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
1513 }
1514 if (type.matches(*fContext.fTypes.fFloat) ||
1515 type.matches(*fContext.fTypes.fInt) ||
1516 type.matches(*fContext.fTypes.fUInt)) {
1517 return "highp ";
1518 }
1519 return "";
1520 case Type::TypeKind::kVector: // fall through
1523 return this->getTypePrecision(type.componentType());
1524 default:
1525 break;
1526 }
1527 }
1528 return "";
1529}
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 1320 of file SkSLGLSLCodeGenerator.cpp.

1320 {
1321 // We can change void-typed user functions to return a (meaningless) float so that sequence
1322 // expressions will work normally in WebGL2. (skbug.com/294893925)
1323 return func &&
1324 !func->isMain() &&
1325 func->returnType().isVoid() &&
1327}
bool fCanUseVoidInSequenceExpressions
Definition: SkSLUtil.h:110

◆ usesPrecisionModifiers()

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

Definition at line 269 of file SkSLGLSLCodeGenerator.cpp.

269 {
271}
bool fUsesPrecisionModifiers
Definition: SkSLUtil.h:95

◆ write()

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

Definition at line 236 of file SkSLGLSLCodeGenerator.cpp.

236 {
237 if (s.empty()) {
238 return;
239 }
240#if defined(SK_DEBUG) || defined(SKSL_STANDALONE)
241 if (fAtLineStart) {
242 for (int i = 0; i < fIndentation; i++) {
243 fOut->writeText(" ");
244 }
245 }
246#endif
247 fOut->write(s.data(), s.length());
248 fAtLineStart = false;
249}
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 1012 of file SkSLGLSLCodeGenerator.cpp.

1012 {
1013 this->writeType(c.type());
1014 this->write("(");
1015 auto separator = SkSL::String::Separator();
1016 for (const auto& arg : c.argumentSpan()) {
1017 this->write(separator());
1018 this->writeExpression(*arg, Precedence::kSequence);
1019 }
1020 this->write(")");
1021}
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 1186 of file SkSLGLSLCodeGenerator.cpp.

1187 {
1188 const Expression& left = *b.left();
1189 const Expression& right = *b.right();
1190 Operator op = b.getOperator();
1191 if (fCaps.fUnfoldShortCircuitAsTernary && (op.kind() == Operator::Kind::LOGICALAND ||
1192 op.kind() == Operator::Kind::LOGICALOR)) {
1193 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
1194 return;
1195 }
1196
1197 if (fCaps.fRewriteMatrixComparisons && left.type().isMatrix() &&
1198 right.type().isMatrix() && op.isEquality()) {
1200 return;
1201 }
1202
1203 Precedence precedence = op.getBinaryPrecedence();
1204 if (precedence >= parentPrecedence) {
1205 this->write("(");
1206 }
1207 const bool needsPositionWorkaround = ProgramConfig::IsVertex(fProgram.fConfig->fKind) &&
1208 op.isAssignment() &&
1209 is_sk_position(left) &&
1212 if (needsPositionWorkaround) {
1213 this->write("sk_FragCoord_Workaround = (");
1214 }
1215 this->writeExpression(left, precedence);
1216 this->write(op.operatorName());
1217
1218 const bool isAssignmentToSampleMask = ProgramConfig::IsFragment(fProgram.fConfig->fKind) &&
1219 op.isAssignment() &&
1220 is_sk_samplemask(left);
1221 if (isAssignmentToSampleMask) {
1222 // GLSL defines the sample masks as signed ints; SkSL (and Metal/WebGPU) use unsigned ints.
1223 this->write("int(");
1224 }
1225 this->writeExpression(right, precedence);
1226 if (isAssignmentToSampleMask) {
1227 this->write(")");
1228 }
1229 if (needsPositionWorkaround) {
1230 this->write(")");
1231 }
1232 if (precedence >= parentPrecedence) {
1233 this->write(")");
1234 }
1235}
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 1653 of file SkSLGLSLCodeGenerator.cpp.

1653 {
1654 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1655 // something here to make the code valid).
1656 bool isScope = b.isScope() || b.isEmpty();
1657 if (isScope) {
1658 this->writeLine("{");
1659 fIndentation++;
1660 }
1661 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1662 if (!stmt->isEmpty()) {
1663 this->writeStatement(*stmt);
1664 this->finishLine();
1665 }
1666 }
1667 if (isScope) {
1668 fIndentation--;
1669 this->write("}");
1670 }
1671}
void writeStatement(const Statement &s)

◆ writeCastConstructor()

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

Definition at line 994 of file SkSLGLSLCodeGenerator.cpp.

994 {
995 const auto arguments = c.argumentSpan();
996 SkASSERT(arguments.size() == 1);
997
998 const Expression& argument = *arguments.front();
999 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
1000 (argument.type().matches(*fContext.fTypes.fFloatLiteral)))) {
1001 // In cases like half(float), they're different types as far as SkSL is concerned but
1002 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
1003 // writing out the inner expression here.
1004 this->writeExpression(argument, parentPrecedence);
1005 return;
1006 }
1007
1008 // This cast should be emitted as-is.
1009 return this->writeAnyConstructor(c, parentPrecedence);
1010}
#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 957 of file SkSLGLSLCodeGenerator.cpp.

958 {
959 // If this is a 2x2 matrix constructor containing a single argument...
960 if (c.type().isMatrix() && c.arguments().size() == 1) {
961 // ... and that argument is a vec4...
962 const Expression& expr = *c.arguments().front();
963 if (expr.type().isVector() && expr.type().columns() == 4) {
964 // ... let's rewrite the cast to dodge issues on very old GPUs. (skia:13559)
966 this->writeType(c.type());
967 this->write("(");
968 this->writeExpression(expr, Precedence::kPostfix);
969 this->write(".xy, ");
970 this->writeExpression(expr, Precedence::kPostfix);
971 this->write(".zw)");
972 } else {
973 std::string tempVec = "_tempVec" + std::to_string(fVarCount++);
974 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(expr.type()) +
975 this->getTypeName(expr.type()) + " " + tempVec + ";\n";
976 this->write("((");
977 this->write(tempVec);
978 this->write(" = ");
979 this->writeExpression(expr, Precedence::kAssignment);
980 this->write("), ");
981 this->writeType(c.type());
982 this->write("(");
983 this->write(tempVec);
984 this->write(".xy, ");
985 this->write(tempVec);
986 this->write(".zw))");
987 }
988 return;
989 }
990 }
991 this->writeAnyConstructor(c, parentPrecedence);
992}
bool IsTrivialExpression(const Expression &expr)

◆ writeConstructorDiagonalMatrix()

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

Definition at line 939 of file SkSLGLSLCodeGenerator.cpp.

940 {
941 if (c.type().columns() == 4 && c.type().rows() == 2) {
942 // Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2
943 // matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646)
944 // We can work around this issue by multiplying a scalar by the identity matrix.
945 // In practice, this doesn't come up naturally in real code and we don't know every affected
946 // driver, so we just apply this workaround everywhere.
947 this->write("(");
948 this->writeType(c.type());
949 this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * ");
950 this->writeExpression(*c.argument(), Precedence::kMultiplicative);
951 this->write(")");
952 return;
953 }
954 this->writeAnyConstructor(c, parentPrecedence);
955}

◆ writeDeterminantHack()

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

Definition at line 517 of file SkSLGLSLCodeGenerator.cpp.

517 {
518 const Type& type = mat.type();
519 if (type.matches(*fContext.fTypes.fFloat2x2) ||
520 type.matches(*fContext.fTypes.fHalf2x2)) {
521 this->write("_determinant2(");
525 }
526 } else if (type.matches(*fContext.fTypes.fFloat3x3) ||
527 type.matches(*fContext.fTypes.fHalf3x3)) {
528 this->write("_determinant3(");
532 }
533 } else if (type.matches(*fContext.fTypes.fFloat4x4) ||
534 type.matches(*fContext.fTypes.fHalf4x4)) {
535 this->write("_determinant4(");
539 }
540 } else {
541 SkDEBUGFAILF("no polyfill for determinant(%s)", type.description().c_str());
542 this->write("determinant(");
543 }
544 this->writeExpression(mat, Precedence::kExpression);
545 this->write(")");
546}
#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 1719 of file SkSLGLSLCodeGenerator.cpp.

1719 {
1721 this->write("do ");
1722 this->writeStatement(*d.statement());
1723 this->write(" while (");
1724 this->writeExpression(*d.test(), Precedence::kExpression);
1725 this->write(");");
1726 return;
1727 }
1728
1729 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1730 // do {
1731 // CODE;
1732 // } while (CONDITION)
1733 //
1734 // to loops of the form
1735 // bool temp = false;
1736 // while (true) {
1737 // if (temp) {
1738 // if (!CONDITION) {
1739 // break;
1740 // }
1741 // }
1742 // temp = true;
1743 // CODE;
1744 // }
1745 std::string tmpVar = "_tmpLoopSeenOnce" + std::to_string(fVarCount++);
1746 this->write("bool ");
1747 this->write(tmpVar);
1748 this->writeLine(" = false;");
1749 this->writeLine("while (true) {");
1750 fIndentation++;
1751 this->write("if (");
1752 this->write(tmpVar);
1753 this->writeLine(") {");
1754 fIndentation++;
1755 this->write("if (!");
1756 this->writeExpression(*d.test(), Precedence::kPrefix);
1757 this->writeLine(") {");
1758 fIndentation++;
1759 this->writeLine("break;");
1760 fIndentation--;
1761 this->writeLine("}");
1762 fIndentation--;
1763 this->writeLine("}");
1764 this->write(tmpVar);
1765 this->writeLine(" = true;");
1766 this->writeStatement(*d.statement());
1767 this->finishLine();
1768 fIndentation--;
1769 this->write("}");
1770}
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 383 of file SkSLGLSLCodeGenerator.cpp.

383 {
384 switch (expr.kind()) {
385 case Expression::Kind::kBinary:
386 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
387 break;
388 case Expression::Kind::kConstructorDiagonalMatrix:
389 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
390 parentPrecedence);
391 break;
392 case Expression::Kind::kConstructorArrayCast:
393 this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence);
394 break;
395 case Expression::Kind::kConstructorCompound:
396 this->writeConstructorCompound(expr.as<ConstructorCompound>(), parentPrecedence);
397 break;
398 case Expression::Kind::kConstructorArray:
399 case Expression::Kind::kConstructorMatrixResize:
400 case Expression::Kind::kConstructorSplat:
401 case Expression::Kind::kConstructorStruct:
402 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
403 break;
404 case Expression::Kind::kConstructorScalarCast:
405 case Expression::Kind::kConstructorCompoundCast:
406 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
407 break;
409 this->write("false");
410 break;
411 case Expression::Kind::kFieldAccess:
412 this->writeFieldAccess(expr.as<FieldAccess>());
413 break;
414 case Expression::Kind::kFunctionCall:
415 this->writeFunctionCall(expr.as<FunctionCall>());
416 break;
418 this->writeLiteral(expr.as<Literal>());
419 break;
420 case Expression::Kind::kPrefix:
421 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
422 break;
423 case Expression::Kind::kPostfix:
424 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
425 break;
426 case Expression::Kind::kSetting:
427 this->writeExpression(*expr.as<Setting>().toLiteral(fCaps), parentPrecedence);
428 break;
429 case Expression::Kind::kSwizzle:
430 this->writeSwizzle(expr.as<Swizzle>());
431 break;
432 case Expression::Kind::kVariableReference:
433 this->writeVariableReference(expr.as<VariableReference>());
434 break;
435 case Expression::Kind::kTernary:
436 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
437 break;
439 this->writeIndexExpression(expr.as<IndexExpression>());
440 break;
441 default:
442 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
443 break;
444 }
445}
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 1772 of file SkSLGLSLCodeGenerator.cpp.

1772 {
1773 if (fProgram.fConfig->fSettings.fOptimize && !Analysis::HasSideEffects(*s.expression())) {
1774 // Don't emit dead expressions.
1775 return;
1776 }
1777 this->writeExpression(*s.expression(), Precedence::kStatement);
1778 this->write(";");
1779}
bool HasSideEffects(const Expression &expr)

◆ writeExtension()

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

Definition at line 263 of file SkSLGLSLCodeGenerator.cpp.

263 {
264 fExtensions.writeText("#extension ");
265 fExtensions.write(name.data(), name.length());
266 fExtensions.writeText(require ? " : require\n" : " : enable\n");
267}
void write(const void *s, size_t size) override
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ writeFieldAccess()

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

Definition at line 1139 of file SkSLGLSLCodeGenerator.cpp.

1139 {
1140 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
1141 this->writeExpression(*f.base(), Precedence::kPostfix);
1142 this->write(".");
1143 }
1144 const Type& baseType = f.base()->type();
1145 int builtin = baseType.fields()[f.fieldIndex()].fLayout.fBuiltin;
1146 if (builtin == SK_POSITION_BUILTIN) {
1147 this->writeIdentifier("gl_Position");
1148 } else if (builtin == SK_POINTSIZE_BUILTIN) {
1149 this->writeIdentifier("gl_PointSize");
1150 } else {
1151 this->writeIdentifier(baseType.fields()[f.fieldIndex()].fName);
1152 }
1153}
constexpr int SK_POSITION_BUILTIN
Definition: SkSLCompiler.h:37
constexpr int SK_POINTSIZE_BUILTIN
Definition: SkSLCompiler.h:38
void writeIdentifier(std::string_view identifier)

◆ writeForStatement()

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

Definition at line 1684 of file SkSLGLSLCodeGenerator.cpp.

1684 {
1685 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1686 if (!f.initializer() && f.test() && !f.next()) {
1687 this->write("while (");
1688 this->writeExpression(*f.test(), Precedence::kExpression);
1689 this->write(") ");
1690 this->writeStatement(*f.statement());
1691 return;
1692 }
1693
1694 this->write("for (");
1695 if (f.initializer() && !f.initializer()->isEmpty()) {
1696 this->writeStatement(*f.initializer());
1697 } else {
1698 this->write("; ");
1699 }
1700 if (f.test()) {
1702 std::unique_ptr<Expression> and_true(new BinaryExpression(
1703 Position(), f.test()->clone(), Operator::Kind::LOGICALAND,
1704 Literal::MakeBool(fContext, Position(), /*value=*/true),
1705 fContext.fTypes.fBool.get()));
1706 this->writeExpression(*and_true, Precedence::kExpression);
1707 } else {
1708 this->writeExpression(*f.test(), Precedence::kExpression);
1709 }
1710 }
1711 this->write("; ");
1712 if (f.next()) {
1713 this->writeExpression(*f.next(), Precedence::kExpression);
1714 }
1715 this->write(") ");
1716 this->writeStatement(*f.statement());
1717}
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 1023 of file SkSLGLSLCodeGenerator.cpp.

1023 {
1024 if (!fCaps.fCanUseFragCoord) {
1026 const char* precision = this->usesPrecisionModifiers() ? "highp " : "";
1027 fFunctionHeader += precision;
1028 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
1029 fFunctionHeader += precision;
1030 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
1031 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
1032 // Ensure that we get exact .5 values for x and y.
1033 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
1034 "vec2(.5);\n";
1036 }
1037 this->writeIdentifier("sk_FragCoord_Resolved");
1038 return;
1039 }
1040
1041 if (!fSetupFragPosition) {
1042 fFunctionHeader += this->usesPrecisionModifiers() ? "highp " : "";
1043 fFunctionHeader += " vec4 sk_FragCoord = vec4("
1044 "gl_FragCoord.x, ";
1045 if (fProgram.fConfig->fSettings.fForceNoRTFlip) {
1046 fFunctionHeader += "gl_FragCoord.y, ";
1047 } else {
1048 fFunctionHeader += SKSL_RTFLIP_NAME ".x + " SKSL_RTFLIP_NAME ".y * gl_FragCoord.y, ";
1049 }
1051 "gl_FragCoord.z, "
1052 "gl_FragCoord.w);\n";
1053 fSetupFragPosition = true;
1054 }
1055 this->writeIdentifier("sk_FragCoord");
1056}
#define SKSL_RTFLIP_NAME
Definition: SkSLProgram.h:19

◆ writeFunction()

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

Definition at line 1381 of file SkSLGLSLCodeGenerator.cpp.

1381 {
1382 fSetupFragPosition = false;
1384 fSetupClockwise = false;
1385 fCurrentFunction = &f.declaration();
1386
1387 this->writeFunctionDeclaration(f.declaration());
1388 this->writeLine(" {");
1389 fIndentation++;
1390
1391 fFunctionHeader.clear();
1392 OutputStream* oldOut = fOut;
1393 StringStream buffer;
1394 fOut = &buffer;
1395 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
1396 if (!stmt->isEmpty()) {
1397 this->writeStatement(*stmt);
1398 this->finishLine();
1399 }
1400 }
1401
1402 if (this->shouldRewriteVoidTypedFunctions(&f.declaration())) {
1403 // If we can't use void in sequence expressions, we rewrite void-typed user functions to
1404 // return a (never-used) float in case they are used in a sequence expression.
1405 this->writeLine("return 0.0;");
1406 }
1407
1408 fIndentation--;
1409 this->writeLine("}");
1410
1411 fOut = oldOut;
1412 this->write(fFunctionHeader);
1413 this->write(buffer.str());
1414
1415 fCurrentFunction = nullptr;
1416}
const FunctionDeclaration * fCurrentFunction
bool shouldRewriteVoidTypedFunctions(const FunctionDeclaration *func) const
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126

◆ writeFunctionCall()

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

Definition at line 672 of file SkSLGLSLCodeGenerator.cpp.

672 {
673 const FunctionDeclaration& function = c.function();
674 const ExpressionArray& arguments = c.arguments();
675 bool isTextureFunctionWithBias = false;
676 bool nameWritten = false;
677 const char* closingParen = ")";
678 switch (c.function().intrinsicKind()) {
679 case k_abs_IntrinsicKind: {
681 break;
682 SkASSERT(arguments.size() == 1);
683 if (!arguments[0]->type().matches(*fContext.fTypes.fInt)) {
684 break;
685 }
686 // abs(int) on Intel OSX is incorrect, so emulate it:
687 this->write("_absemulation");
688 nameWritten = true;
691 fExtraFunctions.writeText("int _absemulation(int x) { return x * sign(x); }\n");
692 }
693 break;
694 }
695 case k_atan_IntrinsicKind:
697 arguments.size() == 2 &&
698 arguments[1]->is<PrefixExpression>()) {
699 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
700 if (p.getOperator().kind() == Operator::Kind::MINUS) {
701 this->write("atan(");
702 this->writeExpression(*arguments[0], Precedence::kSequence);
703 this->write(", -1.0 * ");
704 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
705 this->write(")");
706 return;
707 }
708 }
709 break;
710 case k_ldexp_IntrinsicKind:
712 arguments.size() == 2 &&
713 arguments[1]->is<PrefixExpression>()) {
714 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
715 if (p.getOperator().kind() == Operator::Kind::MINUS) {
716 this->write("ldexp(");
717 this->writeExpression(*arguments[0], Precedence::kSequence);
718 this->write(", ");
719 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
720 this->write(" * -1)");
721 return;
722 }
723 }
724 break;
725 case k_dFdy_IntrinsicKind:
726 // Flipping Y also negates the Y derivatives.
727 closingParen = "))";
728 this->write("(");
729 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
730 this->write(SKSL_RTFLIP_NAME ".y * ");
731 }
732 this->write("dFdy");
733 nameWritten = true;
734 [[fallthrough]];
735 case k_dFdx_IntrinsicKind:
736 case k_fwidth_IntrinsicKind:
737 if (!fFoundDerivatives &&
740 fFoundDerivatives = true;
741 }
742 break;
743 case k_determinant_IntrinsicKind:
745 SkASSERT(arguments.size() == 1);
746 this->writeDeterminantHack(*arguments[0]);
747 return;
748 }
749 break;
750 case k_fma_IntrinsicKind:
752 SkASSERT(arguments.size() == 3);
753 this->write("((");
754 this->writeExpression(*arguments[0], Precedence::kSequence);
755 this->write(") * (");
756 this->writeExpression(*arguments[1], Precedence::kSequence);
757 this->write(") + (");
758 this->writeExpression(*arguments[2], Precedence::kSequence);
759 this->write("))");
760 return;
761 }
762 break;
763 case k_fract_IntrinsicKind:
765 SkASSERT(arguments.size() == 1);
766 this->write("(0.5 - sign(");
767 this->writeExpression(*arguments[0], Precedence::kSequence);
768 this->write(") * (0.5 - fract(abs(");
769 this->writeExpression(*arguments[0], Precedence::kSequence);
770 this->write("))))");
771 return;
772 }
773 break;
774 case k_inverse_IntrinsicKind:
776 SkASSERT(arguments.size() == 1);
777 this->writeInverseHack(*arguments[0]);
778 return;
779 }
780 break;
781 case k_inversesqrt_IntrinsicKind:
783 SkASSERT(arguments.size() == 1);
784 this->writeInverseSqrtHack(*arguments[0]);
785 return;
786 }
787 break;
788 case k_min_IntrinsicKind:
790 SkASSERT(arguments.size() == 2);
791 if (is_abs(*arguments[0])) {
792 this->writeMinAbsHack(*arguments[0], *arguments[1]);
793 return;
794 }
795 if (is_abs(*arguments[1])) {
796 // note that this violates the GLSL left-to-right evaluation semantics.
797 // I doubt it will ever end up mattering, but it's worth calling out.
798 this->writeMinAbsHack(*arguments[1], *arguments[0]);
799 return;
800 }
801 }
802 break;
803 case k_pow_IntrinsicKind:
805 break;
806 }
807 // pow(x, y) on some NVIDIA drivers causes crashes if y is a constant.
808 // It's hard to tell what constitutes "constant" here, so just replace in all cases.
809
810 // Change pow(x, y) into exp2(y * log2(x))
811 this->write("exp2(");
812 this->writeExpression(*arguments[1], Precedence::kMultiplicative);
813 this->write(" * log2(");
814 this->writeExpression(*arguments[0], Precedence::kSequence);
815 this->write("))");
816 return;
817 case k_saturate_IntrinsicKind:
818 SkASSERT(arguments.size() == 1);
819 this->write("clamp(");
820 this->writeExpression(*arguments[0], Precedence::kSequence);
821 this->write(", 0.0, 1.0)");
822 return;
823 case k_sample_IntrinsicKind: {
824 const char* dim = "";
825 bool proj = false;
826 const Type& arg0Type = arguments[0]->type();
827 const Type& arg1Type = arguments[1]->type();
828 switch (arg0Type.dimensions()) {
829 case SpvDim1D:
830 dim = "1D";
831 isTextureFunctionWithBias = true;
832 if (arg1Type.matches(*fContext.fTypes.fFloat)) {
833 proj = false;
834 } else {
835 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat2));
836 proj = true;
837 }
838 break;
839 case SpvDim2D:
840 dim = "2D";
841 if (!arg0Type.matches(*fContext.fTypes.fSamplerExternalOES)) {
842 isTextureFunctionWithBias = true;
843 }
844 if (arg1Type.matches(*fContext.fTypes.fFloat2)) {
845 proj = false;
846 } else {
847 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat3));
848 proj = true;
849 }
850 break;
851 case SpvDim3D:
852 dim = "3D";
853 isTextureFunctionWithBias = true;
854 if (arg1Type.matches(*fContext.fTypes.fFloat3)) {
855 proj = false;
856 } else {
857 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat4));
858 proj = true;
859 }
860 break;
861 case SpvDimCube:
862 dim = "Cube";
863 isTextureFunctionWithBias = true;
864 proj = false;
865 break;
866 case SpvDimRect:
867 dim = "2DRect";
868 proj = false;
869 break;
870 case SpvDimBuffer:
871 SkASSERT(false); // doesn't exist
872 dim = "Buffer";
873 proj = false;
874 break;
876 SkASSERT(false); // doesn't exist
877 dim = "SubpassData";
878 proj = false;
879 break;
880 }
881 this->write("texture");
883 this->write(dim);
884 }
885 if (proj) {
886 this->write("Proj");
887 }
888 nameWritten = true;
889 break;
890 }
891 case k_sampleGrad_IntrinsicKind: {
892 SkASSERT(arguments.size() == 4);
893 this->write("textureGrad");
894 nameWritten = true;
895 break;
896 }
897 case k_sampleLod_IntrinsicKind: {
898 SkASSERT(arguments.size() == 3);
899 this->write("textureLod");
900 nameWritten = true;
901 break;
902 }
903 case k_transpose_IntrinsicKind:
905 SkASSERT(arguments.size() == 1);
906 this->writeTransposeHack(*arguments[0]);
907 return;
908 }
909 break;
910 case k_loadFloatBuffer_IntrinsicKind: {
911 auto indexExpression = IRHelpers::LoadFloatBuffer(
912 fContext,
913 fCaps,
914 c.position(),
915 c.arguments()[0]->clone());
916
917 this->writeExpression(*indexExpression, Precedence::kExpression);
918 return;
919 }
920 default:
921 break;
922 }
923
924 if (!nameWritten) {
925 this->writeIdentifier(function.mangledName());
926 }
927 this->write("(");
928 auto separator = SkSL::String::Separator();
929 for (const auto& arg : arguments) {
930 this->write(separator());
931 this->writeExpression(*arg, Precedence::kSequence);
932 }
933 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
935 }
936 this->write(closingParen);
937}
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)
def matches(file)
Definition: gen_manifest.py:38
@ SpvDimCube
Definition: spirv.h:145
@ SpvDim3D
Definition: spirv.h:144
@ SpvDim2D
Definition: spirv.h:143
@ SpvDim1D
Definition: spirv.h:142
@ SpvDimBuffer
Definition: spirv.h:147
@ SpvDimSubpassData
Definition: spirv.h:148
@ SpvDimRect
Definition: spirv.h:146
static std::unique_ptr< Expression > LoadFloatBuffer(const Context &context, const SkSL::ShaderCaps &shaderCaps, Position position, std::unique_ptr< Expression > idx)
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 1329 of file SkSLGLSLCodeGenerator.cpp.

1329 {
1330 if (this->shouldRewriteVoidTypedFunctions(&f)) {
1331 this->write("float ");
1332 } else {
1333 this->writeTypePrecision(f.returnType());
1334 this->writeType(f.returnType());
1335 this->write(" ");
1336 }
1337 this->writeIdentifier(f.mangledName());
1338 this->write("(");
1339 auto separator = SkSL::String::Separator();
1340 for (size_t index = 0; index < f.parameters().size(); ++index) {
1341 const Variable* param = f.parameters()[index];
1342
1343 // This is a workaround for our test files. They use the runtime effect signature, so main
1344 // takes a coords parameter. We detect these at IR generation time, and we omit them from
1345 // the declaration here, so the function is valid GLSL. (Well, valid as long as the
1346 // coordinates aren't actually referenced.)
1347 if (f.isMain() && param == f.getMainCoordsParameter()) {
1348 continue;
1349 }
1350 this->write(separator());
1351 ModifierFlags flags = param->modifierFlags();
1353 flags &= ~ModifierFlag::kConst;
1354 }
1355 this->writeModifiers(param->layout(), flags, /*globalContext=*/false);
1356 std::vector<int> sizes;
1357 const Type* type = &param->type();
1358 if (type->isArray()) {
1359 sizes.push_back(type->columns());
1360 type = &type->componentType();
1361 }
1362 this->writeTypePrecision(*type);
1363 this->writeType(*type);
1364 this->write(" ");
1365 if (!param->name().empty()) {
1366 this->writeIdentifier(param->mangledName());
1367 } else {
1368 // By the spec, GLSL does not require function parameters to be named (see
1369 // `single_declaration` in the Shading Language Grammar), but some older versions of
1370 // GLSL report "formal parameter lacks a name" if a parameter is not named.
1371 this->write("_skAnonymousParam");
1372 this->write(std::to_string(index));
1373 }
1374 for (int s : sizes) {
1375 this->write("[" + std::to_string(s) + "]");
1376 }
1377 }
1378 this->write(")");
1379}
void writeTypePrecision(const Type &type)
FlutterSemanticsFlag flags
ModifierFlag
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 1418 of file SkSLGLSLCodeGenerator.cpp.

1418 {
1419 this->writeFunctionDeclaration(f.declaration());
1420 this->writeLine(";");
1421}

◆ writeGlobalVarDeclaration()

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

Definition at line 1535 of file SkSLGLSLCodeGenerator.cpp.

1535 {
1536 const VarDeclaration& decl = e.as<GlobalVarDeclaration>().varDeclaration();
1537 switch (decl.var()->layout().fBuiltin) {
1538 case -1:
1539 // normal var
1540 this->writeVarDeclaration(decl, /*global=*/true);
1541 this->finishLine();
1542 break;
1543
1546 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
1547 this->write("inout ");
1548 } else {
1549 this->write("out ");
1550 }
1551 if (this->usesPrecisionModifiers()) {
1552 this->write("mediump ");
1553 }
1554 this->writeLine("vec4 sk_FragColor;");
1555 }
1556 break;
1557
1558 default:
1559 break;
1560 }
1561}
constexpr int SK_FRAGCOLOR_BUILTIN
Definition: SkSLCompiler.h:27
void writeVarDeclaration(const VarDeclaration &var, bool global)
bool mustDeclareFragmentShaderOutput() const
Definition: SkSLUtil.h:43

◆ writeHeader()

void SkSL::GLSLCodeGenerator::writeHeader ( )
protected

Definition at line 1907 of file SkSLGLSLCodeGenerator.cpp.

1907 {
1910 this->finishLine();
1911 }
1912}
const char * fVersionDeclString
Definition: SkSLUtil.h:153

◆ writeIdentifier()

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

Definition at line 273 of file SkSLGLSLCodeGenerator.cpp.

273 {
274 // GLSL forbids two underscores in a row.
275 // If an identifier contains "__" or "_X", replace each "_" in the identifier with "_X".
277 for (const char c : identifier) {
278 if (c == '_') {
279 this->write("_X");
280 } else {
281 this->write(std::string_view(&c, 1));
282 }
283 }
284 } else {
285 this->write(identifier);
286 }
287}
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41

◆ writeIfStatement()

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

Definition at line 1673 of file SkSLGLSLCodeGenerator.cpp.

1673 {
1674 this->write("if (");
1675 this->writeExpression(*stmt.test(), Precedence::kExpression);
1676 this->write(") ");
1677 this->writeStatement(*stmt.ifTrue());
1678 if (stmt.ifFalse()) {
1679 this->write(" else ");
1680 this->writeStatement(*stmt.ifFalse());
1681 }
1682}

◆ writeIndexExpression()

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

Definition at line 1116 of file SkSLGLSLCodeGenerator.cpp.

1116 {
1117 this->writeExpression(*expr.base(), Precedence::kPostfix);
1118 this->write("[");
1119 this->writeExpression(*expr.index(), Precedence::kExpression);
1120 this->write("]");
1121}

◆ writeInputVars()

void SkSL::GLSLCodeGenerator::writeInputVars ( )
protected

Definition at line 1952 of file SkSLGLSLCodeGenerator.cpp.

1952 {
1953 // If we are using sk_FragCoordWorkaround, we don't need to apply RTFlip to gl_FragCoord.
1954 uint8_t useRTFlipUniform = fProgram.fInterface.fRTFlipUniform;
1955 if (!fCaps.fCanUseFragCoord) {
1956 useRTFlipUniform &= ~Program::Interface::kRTFlip_FragCoord;
1957 }
1958
1959 if (useRTFlipUniform != Program::Interface::kRTFlip_None) {
1960 const char* precision = this->usesPrecisionModifiers() ? "highp " : "";
1961 fGlobals.writeText("uniform ");
1962 fGlobals.writeText(precision);
1963 fGlobals.writeText("vec2 " SKSL_RTFLIP_NAME ";\n");
1964 }
1965}
ProgramInterface fInterface
Definition: SkSLProgram.h:165

◆ writeInterfaceBlock()

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

Definition at line 1470 of file SkSLGLSLCodeGenerator.cpp.

1470 {
1471 if (intf.typeName() == "sk_PerVertex") {
1472 return;
1473 }
1474 const Type* structType = &intf.var()->type().componentType();
1475 this->writeModifiers(intf.var()->layout(), intf.var()->modifierFlags(), /*globalContext=*/true);
1476 this->writeType(*structType);
1477 this->writeLine(" {");
1478 fIndentation++;
1479 for (const auto& f : structType->fields()) {
1480 this->writeModifiers(f.fLayout, f.fModifierFlags, /*globalContext=*/false);
1481 this->writeTypePrecision(*f.fType);
1482 this->writeType(*f.fType);
1483 this->write(" ");
1484 this->writeIdentifier(f.fName);
1485 this->writeLine(";");
1486 }
1487 fIndentation--;
1488 this->write("}");
1489 if (!intf.instanceName().empty()) {
1490 this->write(" ");
1491 this->writeIdentifier(intf.instanceName());
1492 if (intf.arraySize() > 0) {
1493 this->write("[");
1494 this->write(std::to_string(intf.arraySize()));
1495 this->write("]");
1496 }
1497 }
1498 this->writeLine(";");
1499}

◆ writeIntrinsicCall()

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

◆ writeInverseHack()

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

Definition at line 611 of file SkSLGLSLCodeGenerator.cpp.

611 {
612 const Type& type = mat.type();
613 if (type.matches(*fContext.fTypes.fFloat2x2) || type.matches(*fContext.fTypes.fHalf2x2)) {
614 this->write("_inverse2(");
615 if (!fWrittenInverse2) {
616 fWrittenInverse2 = true;
618 }
619 } else if (type.matches(*fContext.fTypes.fFloat3x3) ||
620 type.matches(*fContext.fTypes.fHalf3x3)) {
621 this->write("_inverse3(");
622 if (!fWrittenInverse3) {
623 fWrittenInverse3 = true;
625 }
626 } else if (type.matches(*fContext.fTypes.fFloat4x4) ||
627 type.matches(*fContext.fTypes.fHalf4x4)) {
628 this->write("_inverse4(");
629 if (!fWrittenInverse4) {
630 fWrittenInverse4 = true;
632 }
633 } else {
634 SkDEBUGFAILF("no polyfill for inverse(%s)", type.description().c_str());
635 this->write("inverse(");
636 }
637 this->writeExpression(mat, Precedence::kExpression);
638 this->write(")");
639}
static constexpr char kInverse4[]
static constexpr char kInverse3[]
static constexpr char kInverse2[]

◆ writeInverseSqrtHack()

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

Definition at line 469 of file SkSLGLSLCodeGenerator.cpp.

469 {
470 this->write("(1.0 / sqrt(");
471 this->writeExpression(x, Precedence::kExpression);
472 this->write("))");
473}
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 251 of file SkSLGLSLCodeGenerator.cpp.

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

◆ writeLiteral()

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

Definition at line 1305 of file SkSLGLSLCodeGenerator.cpp.

1305 {
1306 const Type& type = l.type();
1307 if (type.isInteger()) {
1308 if (type.matches(*fContext.fTypes.fUInt)) {
1309 this->write(std::to_string(l.intValue() & 0xffffffff) + "u");
1310 } else if (type.matches(*fContext.fTypes.fUShort)) {
1311 this->write(std::to_string(l.intValue() & 0xffff) + "u");
1312 } else {
1313 this->write(std::to_string(l.intValue()));
1314 }
1315 return;
1316 }
1317 this->write(l.description(OperatorPrecedence::kExpression));
1318}

◆ writeMatrixComparisonWorkaround()

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

Definition at line 1161 of file SkSLGLSLCodeGenerator.cpp.

1161 {
1162 const Expression& left = *b.left();
1163 const Expression& right = *b.right();
1164 Operator op = b.getOperator();
1165
1166 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
1167 SkASSERT(left.type().isMatrix());
1168 SkASSERT(right.type().isMatrix());
1169
1170 std::string tempMatrix1 = "_tempMatrix" + std::to_string(fVarCount++);
1171 std::string tempMatrix2 = "_tempMatrix" + std::to_string(fVarCount++);
1172
1173 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(left.type()) +
1174 this->getTypeName(left.type()) + " " + tempMatrix1 + ";\n " +
1175 this->getTypePrecision(right.type()) +
1176 this->getTypeName(right.type()) + " " + tempMatrix2 + ";\n";
1177 this->write("((" + tempMatrix1 + " = ");
1178 this->writeExpression(left, Precedence::kAssignment);
1179 this->write("), (" + tempMatrix2 + " = ");
1180 this->writeExpression(right, Precedence::kAssignment);
1181 this->write("), (" + tempMatrix1);
1182 this->write(op.operatorName());
1183 this->write(tempMatrix2 + "))");
1184}

◆ writeMinAbsHack()

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

Definition at line 454 of file SkSLGLSLCodeGenerator.cpp.

454 {
456 std::string tmpVar1 = "minAbsHackVar" + std::to_string(fVarCount++);
457 std::string tmpVar2 = "minAbsHackVar" + std::to_string(fVarCount++);
458 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(absExpr.type()) +
459 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
460 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(otherExpr.type()) +
461 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
462 this->write("((" + tmpVar1 + " = ");
463 this->writeExpression(absExpr, Precedence::kAssignment);
464 this->write(") < (" + tmpVar2 + " = ");
465 this->writeExpression(otherExpr, Precedence::kAssignment);
466 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
467}

◆ writeModifiers()

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

Definition at line 1423 of file SkSLGLSLCodeGenerator.cpp.

1425 {
1426 this->write(layout.paddedDescription());
1427
1428 // For GLSL 4.1 and below, qualifier-order matters! These are written out in Modifier-bit order.
1429 if (flags & ModifierFlag::kFlat) {
1430 this->write("flat ");
1431 }
1433 this->write("noperspective ");
1434 }
1435
1436 if (flags.isConst()) {
1437 this->write("const ");
1438 }
1439 if (flags.isUniform()) {
1440 this->write("uniform ");
1441 }
1443 this->write("inout ");
1444 } else if (flags & ModifierFlag::kIn) {
1445 if (globalContext && fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
1446 this->write(ProgramConfig::IsVertex(fProgram.fConfig->fKind) ? "attribute "
1447 : "varying ");
1448 } else {
1449 this->write("in ");
1450 }
1451 } else if (flags & ModifierFlag::kOut) {
1452 if (globalContext && fCaps.fGLSLGeneration < SkSL::GLSLGeneration::k130) {
1453 this->write("varying ");
1454 } else {
1455 this->write("out ");
1456 }
1457 }
1458
1459 if (flags.isReadOnly()) {
1460 this->write("readonly ");
1461 }
1462 if (flags.isWriteOnly()) {
1463 this->write("writeonly ");
1464 }
1465 if (flags.isBuffer()) {
1466 this->write("buffer ");
1467 }
1468}

◆ writePostfixExpression()

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

Definition at line 1293 of file SkSLGLSLCodeGenerator.cpp.

1294 {
1295 if (Precedence::kPostfix >= parentPrecedence) {
1296 this->write("(");
1297 }
1298 this->writeExpression(*p.operand(), Precedence::kPostfix);
1299 this->write(p.getOperator().tightOperatorName());
1300 if (Precedence::kPostfix >= parentPrecedence) {
1301 this->write(")");
1302 }
1303}

◆ writePrefixExpression()

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

Definition at line 1281 of file SkSLGLSLCodeGenerator.cpp.

1282 {
1283 if (Precedence::kPrefix >= parentPrecedence) {
1284 this->write("(");
1285 }
1286 this->write(p.getOperator().tightOperatorName());
1287 this->writeExpression(*p.operand(), Precedence::kPrefix);
1288 if (Precedence::kPrefix >= parentPrecedence) {
1289 this->write(")");
1290 }
1291}

◆ writeProgramElement()

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

Definition at line 1914 of file SkSLGLSLCodeGenerator.cpp.

1914 {
1915 switch (e.kind()) {
1917 this->writeExtension(e.as<Extension>().name());
1918 break;
1919
1920 case ProgramElement::Kind::kGlobalVar:
1921 this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
1922 break;
1923
1924 case ProgramElement::Kind::kInterfaceBlock:
1925 this->writeInterfaceBlock(e.as<InterfaceBlock>());
1926 break;
1927
1929 this->writeFunction(e.as<FunctionDefinition>());
1930 break;
1931
1932 case ProgramElement::Kind::kFunctionPrototype:
1933 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1934 break;
1935
1936 case ProgramElement::Kind::kModifiers: {
1937 const ModifiersDeclaration& d = e.as<ModifiersDeclaration>();
1938 this->writeModifiers(d.layout(), d.modifierFlags(), /*globalContext=*/true);
1939 this->writeLine(";");
1940 break;
1941 }
1942 case ProgramElement::Kind::kStructDefinition:
1943 this->writeStructDefinition(e.as<StructDefinition>());
1944 break;
1945
1946 default:
1947 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1948 break;
1949 }
1950}
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 1892 of file SkSLGLSLCodeGenerator.cpp.

1892 {
1894
1895 this->write("return");
1896 if (r.expression()) {
1897 this->write(" ");
1898 this->writeExpression(*r.expression(), Precedence::kExpression);
1900 // We need to rewrite `return` statements to say `return 0.0` since we are converting
1901 // void-typed functions to return floats instead.
1902 this->write(" 0.0");
1903 }
1904 this->write(";");
1905}

◆ writeShortCircuitWorkaroundExpression()

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

Definition at line 1237 of file SkSLGLSLCodeGenerator.cpp.

1238 {
1239 if (Precedence::kTernary >= parentPrecedence) {
1240 this->write("(");
1241 }
1242
1243 // Transform:
1244 // a && b => a ? b : false
1245 // a || b => a ? true : b
1246 this->writeExpression(*b.left(), Precedence::kTernary);
1247 this->write(" ? ");
1248 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
1249 this->writeExpression(*b.right(), Precedence::kTernary);
1250 } else {
1251 Literal boolTrue(Position(), /*value=*/1, fContext.fTypes.fBool.get());
1252 this->writeLiteral(boolTrue);
1253 }
1254 this->write(" : ");
1255 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
1256 Literal boolFalse(Position(), /*value=*/0, fContext.fTypes.fBool.get());
1257 this->writeLiteral(boolFalse);
1258 } else {
1259 this->writeExpression(*b.right(), Precedence::kTernary);
1260 }
1261 if (Precedence::kTernary >= parentPrecedence) {
1262 this->write(")");
1263 }
1264}

◆ writeStatement()

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

Definition at line 1609 of file SkSLGLSLCodeGenerator.cpp.

1609 {
1610 switch (s.kind()) {
1611 case Statement::Kind::kBlock:
1612 this->writeBlock(s.as<Block>());
1613 break;
1614 case Statement::Kind::kExpression:
1615 this->writeExpressionStatement(s.as<ExpressionStatement>());
1616 break;
1617 case Statement::Kind::kReturn:
1618 this->writeReturnStatement(s.as<ReturnStatement>());
1619 break;
1620 case Statement::Kind::kVarDeclaration:
1621 this->writeVarDeclaration(s.as<VarDeclaration>(), /*global=*/false);
1622 break;
1623 case Statement::Kind::kIf:
1624 this->writeIfStatement(s.as<IfStatement>());
1625 break;
1626 case Statement::Kind::kFor:
1627 this->writeForStatement(s.as<ForStatement>());
1628 break;
1629 case Statement::Kind::kDo:
1630 this->writeDoStatement(s.as<DoStatement>());
1631 break;
1632 case Statement::Kind::kSwitch:
1633 this->writeSwitchStatement(s.as<SwitchStatement>());
1634 break;
1635 case Statement::Kind::kBreak:
1636 this->write("break;");
1637 break;
1639 this->write("continue;");
1640 break;
1642 this->write("discard;");
1643 break;
1645 this->write(";");
1646 break;
1647 default:
1648 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
1649 break;
1650 }
1651}
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 357 of file SkSLGLSLCodeGenerator.cpp.

357 {
358 const Type& type = s.type();
359 this->write("struct ");
360 this->writeIdentifier(type.name());
361 this->writeLine(" {");
362 fIndentation++;
363 for (const auto& f : type.fields()) {
364 this->writeModifiers(f.fLayout, f.fModifierFlags, /*globalContext=*/false);
365 this->writeTypePrecision(*f.fType);
366 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
367 this->writeType(baseType);
368 this->write(" ");
369 this->writeIdentifier(f.fName);
370 if (f.fType->isArray()) {
371 this->write("[" + std::to_string(f.fType->columns()) + "]");
372 }
373 this->writeLine(";");
374 }
375 fIndentation--;
376 this->writeLine("};");
377}

◆ writeSwitchStatement()

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

Definition at line 1781 of file SkSLGLSLCodeGenerator.cpp.

1781 {
1783 std::string fallthroughVar = "_tmpSwitchFallthrough" + std::to_string(fVarCount++);
1784 std::string valueVar = "_tmpSwitchValue" + std::to_string(fVarCount++);
1785 std::string loopVar = "_tmpSwitchLoop" + std::to_string(fVarCount++);
1786 this->write("int ");
1787 this->write(valueVar);
1788 this->write(" = ");
1789 this->writeExpression(*s.value(), Precedence::kAssignment);
1790 this->write(", ");
1791 this->write(fallthroughVar);
1792 this->writeLine(" = 0;");
1793 this->write("for (int ");
1794 this->write(loopVar);
1795 this->write(" = 0; ");
1796 this->write(loopVar);
1797 this->write(" < 1; ");
1798 this->write(loopVar);
1799 this->writeLine("++) {");
1800 fIndentation++;
1801
1802 bool firstCase = true;
1803 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1804 const SwitchCase& c = stmt->as<SwitchCase>();
1805 if (!c.isDefault()) {
1806 this->write("if ((");
1807 if (firstCase) {
1808 firstCase = false;
1809 } else {
1810 this->write(fallthroughVar);
1811 this->write(" > 0) || (");
1812 }
1813 this->write(valueVar);
1814 this->write(" == ");
1815 this->write(std::to_string(c.value()));
1816 this->writeLine(")) {");
1817 fIndentation++;
1818
1819 // We write the entire case-block statement here, and then set `switchFallthrough`
1820 // to 1. If the case-block had a break statement in it, we break out of the outer
1821 // for-loop entirely, meaning the `switchFallthrough` assignment never occurs, nor
1822 // does any code after it inside the switch. We've forbidden `continue` statements
1823 // inside switch case-blocks entirely, so we don't need to consider their effect on
1824 // control flow; see the Finalizer in FunctionDefinition::Convert.
1825 this->writeStatement(*c.statement());
1826 this->finishLine();
1827 this->write(fallthroughVar);
1828 this->write(" = 1;");
1829 this->writeLine();
1830
1831 fIndentation--;
1832 this->writeLine("}");
1833 } else {
1834 // This is the default case. Since it's always last, we can just dump in the code.
1835 this->writeStatement(*c.statement());
1836 this->finishLine();
1837 }
1838 }
1839
1840 fIndentation--;
1841 this->writeLine("}");
1842 return;
1843 }
1844
1845 this->write("switch (");
1846 this->writeExpression(*s.value(), Precedence::kExpression);
1847 this->writeLine(") {");
1848 fIndentation++;
1849 // If a switch contains only a `default` case and nothing else, this confuses some drivers and
1850 // can lead to a crash. Adding a real case before the default seems to work around the bug,
1851 // and doesn't change the meaning of the switch. (skia:12465)
1852 if (s.cases().size() == 1 && s.cases().front()->as<SwitchCase>().isDefault()) {
1853 this->writeLine("case 0:");
1854 }
1855
1856 // The GLSL spec insists that the last case in a switch statement must have an associated
1857 // statement. In practice, the Apple GLSL compiler crashes if that statement is a no-op, such as
1858 // a semicolon or an empty brace pair. (This is filed as FB11992149.) It also crashes if we put
1859 // two `break` statements in a row. To work around this while honoring the rules of the
1860 // standard, we inject an extra break if and only if the last switch-case block is empty.
1861 bool foundEmptyCase = false;
1862
1863 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1864 const SwitchCase& c = stmt->as<SwitchCase>();
1865 if (c.isDefault()) {
1866 this->writeLine("default:");
1867 } else {
1868 this->write("case ");
1869 this->write(std::to_string(c.value()));
1870 this->writeLine(":");
1871 }
1872 if (c.statement()->isEmpty()) {
1873 foundEmptyCase = true;
1874 } else {
1875 foundEmptyCase = false;
1876 fIndentation++;
1877 this->writeStatement(*c.statement());
1878 this->finishLine();
1879 fIndentation--;
1880 }
1881 }
1882 if (foundEmptyCase) {
1883 fIndentation++;
1884 this->writeLine("break;");
1885 fIndentation--;
1886 }
1887 fIndentation--;
1888 this->finishLine();
1889 this->write("}");
1890}
bool fRewriteSwitchStatements
Definition: SkSLUtil.h:133

◆ writeSwizzle()

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

Definition at line 1155 of file SkSLGLSLCodeGenerator.cpp.

1155 {
1156 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
1157 this->write(".");
1158 this->write(Swizzle::MaskString(swizzle.components()));
1159}
static std::string MaskString(const ComponentArray &inComponents)

◆ writeTernaryExpression()

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

Definition at line 1266 of file SkSLGLSLCodeGenerator.cpp.

1267 {
1268 if (Precedence::kTernary >= parentPrecedence) {
1269 this->write("(");
1270 }
1271 this->writeExpression(*t.test(), Precedence::kTernary);
1272 this->write(" ? ");
1273 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
1274 this->write(" : ");
1275 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
1276 if (Precedence::kTernary >= parentPrecedence) {
1277 this->write(")");
1278 }
1279}

◆ writeTransposeHack()

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

Definition at line 641 of file SkSLGLSLCodeGenerator.cpp.

641 {
642 const Type& type = mat.type();
643 int c = type.columns();
644 int r = type.rows();
645 std::string name = "transpose" + std::to_string(c) + std::to_string(r);
646
647 SkASSERT(c >= 2 && c <= 4);
648 SkASSERT(r >= 2 && r <= 4);
649 bool* writtenThisTranspose = &fWrittenTranspose[c - 2][r - 2];
650 if (!*writtenThisTranspose) {
651 *writtenThisTranspose = true;
652 std::string typeName = this->getTypeName(type);
653 const Type& base = type.componentType();
654 std::string transposed = this->getTypeName(base.toCompound(fContext, r, c));
655 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) { return " +
656 transposed + "(").c_str());
657 auto separator = SkSL::String::Separator();
658 for (int row = 0; row < r; ++row) {
659 for (int column = 0; column < c; ++column) {
660 fExtraFunctions.writeText(separator().c_str());
661 fExtraFunctions.writeText(("m[" + std::to_string(column) + "][" +
662 std::to_string(row) + "]").c_str());
663 }
664 }
665 fExtraFunctions.writeText("); }\n");
666 }
667 this->write(name + "(");
668 this->writeExpression(mat, Precedence::kExpression);
669 this->write(")");
670}

◆ writeType()

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

Definition at line 379 of file SkSLGLSLCodeGenerator.cpp.

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

◆ writeTypePrecision()

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

Definition at line 1531 of file SkSLGLSLCodeGenerator.cpp.

1531 {
1532 this->write(this->getTypePrecision(type));
1533}

◆ writeVarDeclaration()

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

Definition at line 1563 of file SkSLGLSLCodeGenerator.cpp.

1563 {
1564 const Variable* var = decl.var();
1565 this->writeModifiers(var->layout(), var->modifierFlags(), global);
1566
1567 if (global && !var->modifierFlags().isUniform()) {
1568 if (decl.baseType().typeKind() == Type::TypeKind::kSampler ||
1569 decl.baseType().typeKind() == Type::TypeKind::kSeparateSampler ||
1570 decl.baseType().typeKind() == Type::TypeKind::kTexture) {
1571 // We don't require the `uniform` modifier on textures/samplers, but GLSL does.
1572 this->write("uniform ");
1573 }
1574 }
1575
1576 this->writeTypePrecision(decl.baseType());
1577 this->writeType(decl.baseType());
1578 this->write(" ");
1579 this->writeIdentifier(var->mangledName());
1580 if (decl.arraySize() > 0) {
1581 this->write("[");
1582 this->write(std::to_string(decl.arraySize()));
1583 this->write("]");
1584 }
1585 if (decl.value()) {
1586 this->write(" = ");
1587 this->writeVarInitializer(*var, *decl.value());
1588 }
1590 var->type().matches(*fContext.fTypes.fSamplerExternalOES)) {
1592 fContext.fErrors->error(decl.position(), "external texture support is not enabled");
1593 } else {
1596 }
1599 }
1601 }
1602 }
1603 if (!fFoundRectSamplerDecl && var->type().matches(*fContext.fTypes.fSampler2DRect)) {
1604 fFoundRectSamplerDecl = true;
1605 }
1606 this->write(";");
1607}
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 1058 of file SkSLGLSLCodeGenerator.cpp.

1058 {
1059 switch (ref.variable()->layout().fBuiltin) {
1062 this->writeIdentifier("sk_FragColor");
1063 } else {
1064 this->writeIdentifier("gl_FragColor");
1065 }
1066 break;
1069 this->writeIdentifier("gl_SecondaryFragColorEXT");
1070 } else {
1071 fContext.fErrors->error(ref.position(), "'sk_SecondaryFragColor' not supported");
1072 }
1073 break;
1075 this->writeFragCoord();
1076 break;
1078 if (!fSetupClockwise) {
1079 fFunctionHeader += " bool sk_Clockwise = gl_FrontFacing;\n";
1080 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
1081 fFunctionHeader += " if (" SKSL_RTFLIP_NAME ".y < 0.0) {\n"
1082 " sk_Clockwise = !sk_Clockwise;\n"
1083 " }\n";
1084 }
1085 fSetupClockwise = true;
1086 }
1087 this->writeIdentifier("sk_Clockwise");
1088 break;
1090 this->writeIdentifier("gl_VertexID");
1091 break;
1093 this->writeIdentifier("gl_InstanceID");
1094 break;
1098 } else {
1099 fContext.fErrors->error(ref.position(), "'sk_LastFragColor' not supported");
1100 }
1101 break;
1103 // GLSL defines gl_SampleMaskIn as an array of ints. SkSL defines it as a scalar uint.
1104 this->writeIdentifier("uint(gl_SampleMaskIn[0])");
1105 break;
1107 // GLSL defines gl_SampleMask as an array of ints. SkSL defines it as a scalar uint.
1108 this->writeIdentifier("gl_SampleMask[0]");
1109 break;
1110 default:
1111 this->writeIdentifier(ref.variable()->mangledName());
1112 break;
1113 }
1114}
constexpr int SK_SAMPLEMASK_BUILTIN
Definition: SkSLCompiler.h:33
constexpr int SK_CLOCKWISE_BUILTIN
Definition: SkSLCompiler.h:31
constexpr int SK_VERTEXID_BUILTIN
Definition: SkSLCompiler.h:35
constexpr int SK_LASTFRAGCOLOR_BUILTIN
Definition: SkSLCompiler.h:28
constexpr int SK_INSTANCEID_BUILTIN
Definition: SkSLCompiler.h:36
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
Definition: SkSLCompiler.h:29
constexpr int SK_FRAGCOORD_BUILTIN
Definition: SkSLCompiler.h:30
constexpr int SK_SAMPLEMASKIN_BUILTIN
Definition: SkSLCompiler.h:32
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 1501 of file SkSLGLSLCodeGenerator.cpp.

1501 {
1502 this->writeExpression(value, Precedence::kExpression);
1503}
uint8_t value

Member Data Documentation

◆ fAtLineStart

bool SkSL::GLSLCodeGenerator::fAtLineStart = false
protected

Definition at line 216 of file SkSLGLSLCodeGenerator.cpp.

◆ fCurrentFunction

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

Definition at line 217 of file SkSLGLSLCodeGenerator.cpp.

◆ fExtensions

StringStream SkSL::GLSLCodeGenerator::fExtensions
protected

Definition at line 210 of file SkSLGLSLCodeGenerator.cpp.

◆ fExtraFunctions

StringStream SkSL::GLSLCodeGenerator::fExtraFunctions
protected

Definition at line 212 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundDerivatives

bool SkSL::GLSLCodeGenerator::fFoundDerivatives = false
protected

Definition at line 220 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundExternalSamplerDecl

bool SkSL::GLSLCodeGenerator::fFoundExternalSamplerDecl = false
protected

Definition at line 221 of file SkSLGLSLCodeGenerator.cpp.

◆ fFoundRectSamplerDecl

bool SkSL::GLSLCodeGenerator::fFoundRectSamplerDecl = false
protected

Definition at line 222 of file SkSLGLSLCodeGenerator.cpp.

◆ fFunctionHeader

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

Definition at line 213 of file SkSLGLSLCodeGenerator.cpp.

◆ fGlobals

StringStream SkSL::GLSLCodeGenerator::fGlobals
protected

Definition at line 211 of file SkSLGLSLCodeGenerator.cpp.

◆ fIndentation

int SkSL::GLSLCodeGenerator::fIndentation = 0
protected

Definition at line 215 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupClockwise

bool SkSL::GLSLCodeGenerator::fSetupClockwise = false
protected

Definition at line 223 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupFragCoordWorkaround

bool SkSL::GLSLCodeGenerator::fSetupFragCoordWorkaround = false
protected

Definition at line 225 of file SkSLGLSLCodeGenerator.cpp.

◆ fSetupFragPosition

bool SkSL::GLSLCodeGenerator::fSetupFragPosition = false
protected

Definition at line 224 of file SkSLGLSLCodeGenerator.cpp.

◆ fVarCount

int SkSL::GLSLCodeGenerator::fVarCount = 0
protected

Definition at line 214 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenAbsEmulation

bool SkSL::GLSLCodeGenerator::fWrittenAbsEmulation = false
protected

Definition at line 228 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant2

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant2 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant3

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant3 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenDeterminant4

bool SkSL::GLSLCodeGenerator::fWrittenDeterminant4 = false
protected

Definition at line 229 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse2

bool SkSL::GLSLCodeGenerator::fWrittenInverse2 = false
protected

Definition at line 230 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse3

bool SkSL::GLSLCodeGenerator::fWrittenInverse3 = false
protected

Definition at line 230 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenInverse4

bool SkSL::GLSLCodeGenerator::fWrittenInverse4 = false
protected

Definition at line 230 of file SkSLGLSLCodeGenerator.cpp.

◆ fWrittenTranspose

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

Definition at line 231 of file SkSLGLSLCodeGenerator.cpp.


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