82#include <initializer_list>
101 ,
fReservedWords({
"atan2",
"rsqrt",
"rint",
"dfdx",
"dfdy",
"vertex",
"fragment"})
127 void write(std::string_view
s);
129 void writeLine(std::string_view
s = std::string_view());
176 const char*& separator);
251 const char* leftBracket,
252 const char* rightBracket,
256 const char* leftBracket,
257 const char* rightBracket,
374 case Operator::Kind::LOGICALXOR:
return " != ";
399#if defined(SK_DEBUG) || defined(SKSL_STANDALONE)
423 this->
writeLine(
"#extension " + std::string(
ext.name()) +
" : enable");
429 switch (
type.typeKind()) {
432 SkASSERTF(
type.columns() > 0,
"invalid array size: %s",
type.description().c_str());
450 switch (
type.textureAccess()) {
462 return "atomic_uint";
465 return std::string(
type.name());
483 switch (expr.
kind()) {
484 case Expression::Kind::kBinary:
487 case Expression::Kind::kConstructorArray:
488 case Expression::Kind::kConstructorStruct:
491 case Expression::Kind::kConstructorArrayCast:
494 case Expression::Kind::kConstructorCompound:
497 case Expression::Kind::kConstructorDiagonalMatrix:
498 case Expression::Kind::kConstructorSplat:
501 case Expression::Kind::kConstructorMatrixResize:
505 case Expression::Kind::kConstructorScalarCast:
506 case Expression::Kind::kConstructorCompoundCast:
510 this->
write(
"false");
512 case Expression::Kind::kFieldAccess:
518 case Expression::Kind::kFunctionCall:
521 case Expression::Kind::kPrefix:
524 case Expression::Kind::kPostfix:
527 case Expression::Kind::kSetting:
530 case Expression::Kind::kSwizzle:
533 case Expression::Kind::kVariableReference:
536 case Expression::Kind::kTernary:
573 auto oldIndexSubstitutionData = std::make_unique<IndexSubstitutionData>();
615 bool foundOutParam =
false;
619 for (
int index = 0; index < arguments.
size(); ++index) {
627 foundOutParam =
true;
652 std::string scratchResultName;
653 if (!
function.returnType().isVoid()) {
655 this->
write(scratchResultName);
664 const char* separator =
"";
667 for (
int i = 0;
i < arguments.
size(); ++
i) {
668 this->
write(separator);
676 this->
write(scratchVarName[
i]);
682 this->
write(scratchVarName[
i]);
694 for (
int i = 0;
i < arguments.
size(); ++
i) {
695 if (!scratchVarName[
i].
empty()) {
699 this->
write(scratchVarName[
i]);
706 if (!scratchResultName.empty()) {
708 this->
write(scratchResultName);
719 const char* separator =
"";
721 for (
int i = 0;
i < arguments.
size(); ++
i) {
723 this->
write(separator);
733matrix<T, 2, 2> mat2_inverse(matrix<T, 2, 2> m) {
734return matrix<T, 2, 2>(m[1].y, -m[0].y, -m[1].x, m[0].x) * (1/determinant(m));
740matrix<T, 3, 3> mat3_inverse(matrix<T, 3, 3> m) {
742 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
743 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
744 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
745 b01 = a22*a11 - a12*a21,
746 b11 = -a22*a10 + a12*a20,
747 b21 = a21*a10 - a11*a20,
748 det = a00*b01 + a01*b11 + a02*b21;
749return matrix<T, 3, 3>(
750 b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),
751 b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),
752 b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) * (1/det);
758matrix<T, 4, 4> mat4_inverse(matrix<T, 4, 4> m) {
760 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z, a03 = m[0].w,
761 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z, a13 = m[1].w,
762 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z, a23 = m[2].w,
763 a30 = m[3].x, a31 = m[3].y, a32 = m[3].z, a33 = m[3].w,
764 b00 = a00*a11 - a01*a10,
765 b01 = a00*a12 - a02*a10,
766 b02 = a00*a13 - a03*a10,
767 b03 = a01*a12 - a02*a11,
768 b04 = a01*a13 - a03*a11,
769 b05 = a02*a13 - a03*a12,
770 b06 = a20*a31 - a21*a30,
771 b07 = a20*a32 - a22*a30,
772 b08 = a20*a33 - a23*a30,
773 b09 = a21*a32 - a22*a31,
774 b10 = a21*a33 - a23*a31,
775 b11 = a22*a33 - a23*a32,
776 det = b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06;
777return matrix<T, 4, 4>(
778 a11*b11 - a12*b10 + a13*b09,
779 a02*b10 - a01*b11 - a03*b09,
780 a31*b05 - a32*b04 + a33*b03,
781 a22*b04 - a21*b05 - a23*b03,
782 a12*b08 - a10*b11 - a13*b07,
783 a00*b11 - a02*b08 + a03*b07,
784 a32*b02 - a30*b05 - a33*b01,
785 a20*b05 - a22*b02 + a23*b01,
786 a10*b10 - a11*b08 + a13*b06,
787 a01*b08 - a00*b10 - a03*b06,
788 a30*b04 - a31*b02 + a33*b00,
789 a21*b02 - a20*b04 - a23*b00,
790 a11*b07 - a10*b09 - a12*b06,
791 a00*b09 - a01*b07 + a02*b06,
792 a31*b01 - a30*b03 - a32*b00,
793 a20*b03 - a21*b01 + a22*b00) * (1/det);
802 switch (
type.rows()) {
808 return "mat2_inverse";
814 return "mat3_inverse";
820 return "mat4_inverse";
828 static constexpr char kMatrixCompMult[] = R
"(
829template <typename T, int C, int R>
830matrix<T, C, R> matrixCompMult(matrix<T, C, R> a, const matrix<T, C, R> b) {
831 for (int c = 0; c < C; ++c) { a[c] *= b[c]; }
842 static constexpr char kOuterProduct[] = R
"(
843template <typename T, int C, int R>
844matrix<T, C, R> outerProduct(const vec<T, R> a, const vec<T, C> b) {
846 for (int c = 0; c < C; ++c) { m[c] = a * b[c]; }
870 const char* separator =
"";
871 for (
const std::unique_ptr<Expression>& arg : arguments) {
872 this->
write(separator);
882 case k_textureRead_IntrinsicKind: {
884 this->
write(
".read(");
889 case k_textureWrite_IntrinsicKind: {
891 this->
write(
".write(");
898 case k_textureWidth_IntrinsicKind: {
900 this->
write(
".get_width()");
903 case k_textureHeight_IntrinsicKind: {
905 this->
write(
".get_height()");
908 case k_mod_IntrinsicKind: {
912 this->
write(
"(" + tmpX +
" = ");
914 this->
write(
", " + tmpY +
" = ");
916 this->
write(
", " + tmpX +
" - " + tmpY +
" * floor(" + tmpX +
" / " + tmpY +
"))");
920 case k_distance_IntrinsicKind: {
921 if (arguments[0]->
type().columns() == 1) {
932 case k_dot_IntrinsicKind: {
933 if (arguments[0]->
type().columns() == 1) {
944 case k_faceforward_IntrinsicKind: {
945 if (arguments[0]->
type().columns() == 1) {
949 this->
write(
") * (");
951 this->
write(
") < 0) ? 1 : -1) * (");
959 case k_length_IntrinsicKind: {
960 this->
write(arguments[0]->
type().columns() == 1 ?
"abs(" :
"length(");
965 case k_normalize_IntrinsicKind: {
966 this->
write(arguments[0]->
type().columns() == 1 ?
"sign(" :
"normalize(");
971 case k_packUnorm2x16_IntrinsicKind: {
972 this->
write(
"pack_float_to_unorm2x16(");
977 case k_unpackUnorm2x16_IntrinsicKind: {
978 this->
write(
"unpack_unorm2x16_to_float(");
983 case k_packSnorm2x16_IntrinsicKind: {
984 this->
write(
"pack_float_to_snorm2x16(");
989 case k_unpackSnorm2x16_IntrinsicKind: {
990 this->
write(
"unpack_snorm2x16_to_float(");
995 case k_packUnorm4x8_IntrinsicKind: {
996 this->
write(
"pack_float_to_unorm4x8(");
1001 case k_unpackUnorm4x8_IntrinsicKind: {
1002 this->
write(
"unpack_unorm4x8_to_float(");
1007 case k_packSnorm4x8_IntrinsicKind: {
1008 this->
write(
"pack_float_to_snorm4x8(");
1013 case k_unpackSnorm4x8_IntrinsicKind: {
1014 this->
write(
"unpack_snorm4x8_to_float(");
1019 case k_packHalf2x16_IntrinsicKind: {
1020 this->
write(
"as_type<uint>(half2(");
1025 case k_unpackHalf2x16_IntrinsicKind: {
1026 this->
write(
"float2(as_type<half2>(");
1031 case k_floatBitsToInt_IntrinsicKind:
1032 case k_floatBitsToUint_IntrinsicKind:
1033 case k_intBitsToFloat_IntrinsicKind:
1034 case k_uintBitsToFloat_IntrinsicKind: {
1041 case k_degrees_IntrinsicKind: {
1044 this->
write(
") * 57.2957795)");
1047 case k_radians_IntrinsicKind: {
1050 this->
write(
") * 0.0174532925)");
1053 case k_dFdx_IntrinsicKind: {
1054 this->
write(
"dfdx");
1058 case k_dFdy_IntrinsicKind: {
1062 this->
write(
"(dfdy");
1068 case k_inverse_IntrinsicKind: {
1073 case k_inversesqrt_IntrinsicKind: {
1074 this->
write(
"rsqrt");
1078 case k_atan_IntrinsicKind: {
1083 case k_reflect_IntrinsicKind: {
1084 if (arguments[0]->
type().columns() == 1) {
1090 this->
write(
"(" + tmpI +
" = ");
1094 this->
write(
", " + tmpN +
" = ");
1098 this->
write(
", " + tmpI +
" - 2 * " + tmpN +
" * " + tmpI +
" * " + tmpN +
")");
1104 case k_refract_IntrinsicKind: {
1105 if (arguments[0]->
type().columns() == 1) {
1108 this->
write(
"(refract(float2(");
1110 this->
write(
", 0), float2(");
1112 this->
write(
", 0), ");
1114 this->
write(
").x)");
1120 case k_roundEven_IntrinsicKind: {
1121 this->
write(
"rint");
1125 case k_bitCount_IntrinsicKind: {
1126 this->
write(
"popcount(");
1131 case k_findLSB_IntrinsicKind: {
1134 std::string exprType = this->
typeName(arguments[0]->
type());
1141 this->
write(skTemp);
1142 this->
write(
" = (");
1144 this->
write(
"), select(ctz(");
1145 this->
write(skTemp);
1147 this->
write(exprType);
1148 this->
write(
"(-1), ");
1149 this->
write(skTemp);
1150 this->
write(
" == ");
1151 this->
write(exprType);
1152 this->
write(
"(0)))");
1155 case k_findMSB_IntrinsicKind: {
1158 std::string exprType = this->
typeName(arguments[0]->
type());
1166 this->
write(skTemp1);
1167 this->
write(
" = (");
1173 std::string skTemp2;
1174 if (arguments[0]->
type().isSigned()) {
1177 this->
write(skTemp2);
1178 this->
write(
" = (select(");
1179 this->
write(skTemp1);
1181 this->
write(skTemp1);
1183 this->
write(skTemp1);
1184 this->
write(
" < 0)), ");
1190 this->
write(
"select(");
1192 this->
write(
"(clz(");
1193 this->
write(skTemp2);
1194 this->
write(
")), ");
1196 this->
write(
"(-1), ");
1197 this->
write(skTemp2);
1198 this->
write(
" == ");
1199 this->
write(exprType);
1200 this->
write(
"(0)))");
1203 case k_sign_IntrinsicKind: {
1204 if (arguments[0]->
type().componentType().isInteger()) {
1207 std::string exprType = this->
typeName(arguments[0]->
type());
1211 this->
write(skTemp);
1212 this->
write(
" = (");
1217 this->
write(
"select(select(");
1218 this->
write(exprType);
1219 this->
write(
"(0), ");
1220 this->
write(exprType);
1221 this->
write(
"(-1), ");
1222 this->
write(skTemp);
1223 this->
write(
" < 0), ");
1224 this->
write(exprType);
1225 this->
write(
"(1), ");
1226 this->
write(skTemp);
1227 this->
write(
" > 0))");
1233 case k_matrixCompMult_IntrinsicKind: {
1238 case k_outerProduct_IntrinsicKind: {
1243 case k_mix_IntrinsicKind: {
1245 if (arguments[2]->
type().componentType().isBoolean()) {
1247 this->
write(
"select");
1255 case k_equal_IntrinsicKind:
1256 case k_greaterThan_IntrinsicKind:
1257 case k_greaterThanEqual_IntrinsicKind:
1258 case k_lessThan_IntrinsicKind:
1259 case k_lessThanEqual_IntrinsicKind:
1260 case k_notEqual_IntrinsicKind: {
1264 case k_equal_IntrinsicKind:
1265 this->
write(
" == ");
1267 case k_notEqual_IntrinsicKind:
1268 this->
write(
" != ");
1270 case k_lessThan_IntrinsicKind:
1273 case k_lessThanEqual_IntrinsicKind:
1274 this->
write(
" <= ");
1276 case k_greaterThan_IntrinsicKind:
1279 case k_greaterThanEqual_IntrinsicKind:
1280 this->
write(
" >= ");
1283 SK_ABORT(
"unsupported comparison intrinsic kind");
1289 case k_storageBarrier_IntrinsicKind:
1290 this->
write(
"threadgroup_barrier(mem_flags::mem_device)");
1292 case k_workgroupBarrier_IntrinsicKind:
1293 this->
write(
"threadgroup_barrier(mem_flags::mem_threadgroup)");
1295 case k_atomicAdd_IntrinsicKind:
1296 this->
write(
"atomic_fetch_add_explicit(&");
1300 this->
write(
", memory_order_relaxed)");
1302 case k_atomicLoad_IntrinsicKind:
1303 this->
write(
"atomic_load_explicit(&");
1305 this->
write(
", memory_order_relaxed)");
1307 case k_atomicStore_IntrinsicKind:
1308 this->
write(
"atomic_store_explicit(&");
1312 this->
write(
", memory_order_relaxed)");
1314 case k_loadFloatBuffer_IntrinsicKind: {
1337 const char* separator =
"";
1338 for (
int c = 0; c < columns; ++c) {
1343 int swizzleLength = 0;
1344 if (c < sourceMatrix.
columns()) {
1345 swizzleLength = std::min<>(rows, sourceMatrix.
rows());
1350 switch (swizzleLength) {
1351 case 0: firstItem =
true;
break;
1360 for (
int r = swizzleLength; r < rows; ++r) {
1378 size_t argIndex = 0;
1379 int argPosition = 0;
1382 static constexpr char kSwizzle[] =
"xyzw";
1383 const char* separator =
"";
1384 for (
int c = 0; c < columns; ++c) {
1388 const char* columnSeparator =
"";
1389 for (
int r = 0; r < rows;) {
1391 columnSeparator =
", ";
1393 if (argIndex <
args.size()) {
1394 const Type& argType =
args[argIndex]->type();
1408 }
while (r < rows && argPosition < argType.
columns());
1417 }
while (r < rows && (argPosition % argType.
rows()) != 0);
1421 SkDEBUGFAIL(
"incorrect type of argument for matrix constructor");
1427 if (argPosition >= argType.
columns() * argType.
rows()) {
1432 SkDEBUGFAIL(
"not enough arguments for matrix constructor");
1438 if (argPosition != 0 || argIndex !=
args.size()) {
1439 SkDEBUGFAIL(
"incorrect number of arguments for matrix constructor");
1452 int columns =
type.columns();
1453 int rows =
type.rows();
1459 for (
const std::unique_ptr<Expression>& expr :
args) {
1472 size_t argIndex = 0;
1473 const char* argSeparator =
"";
1474 for (
const std::unique_ptr<Expression>& expr :
args) {
1476 this->
typeName(expr->type()).c_str(), argIndex++);
1477 argSeparator =
", ";
1482 if (
args.size() == 1 &&
args.front()->type().isMatrix()) {
1518 for (
const std::unique_ptr<Expression>& expr : c.
arguments()) {
1520 if (expr->type().isMatrix()) {
1523 position += expr->type().columns();
1560 const Type& inType = c.
argument()->type().componentType();
1562 std::string inTypeName = this->
typeName(inType);
1563 std::string outTypeName = this->
typeName(outType);
1565 std::string
name =
"array_of_" + outTypeName +
"_from_" + inTypeName;
1570array<%s, N> %s(thread const array<%s, N>& x) {
1571 array<%s, N> result;
1572 for (int i = 0; i < N; ++i) {
1573 result[i] = %s(x[i]);
1578 outTypeName.c_str(), name.c_str(), inTypeName.c_str(),
1579 outTypeName.c_str(),
1580 outTypeName.c_str());
1595 std::string
name =
String::printf(
"%s4_from_%s2x2", baseType.c_str(), baseType.c_str());
1601 return %s4(x[0].xy, x[1].xy);
1603)", baseType.c_str(), name.c_str(), baseType.c_str(), baseType.c_str());
1637 const char* separator =
"";
1638 for (
const std::unique_ptr<Expression>& expr : c.
arguments()) {
1639 this->
write(separator);
1656 const char* separator =
"";
1657 int scalarCount = 0;
1658 for (
const std::unique_ptr<Expression>& arg : c.
arguments()) {
1659 this->
write(separator);
1661 if (arg->type().columns() < matrixType.
rows()) {
1667 scalarCount += arg->type().columns();
1670 if (scalarCount && scalarCount == matrixType.
rows()) {
1680 const char* leftBracket,
1681 const char* rightBracket,
1684 this->
write(leftBracket);
1685 const char* separator =
"";
1686 for (
const std::unique_ptr<Expression>& arg : c.
argumentSpan()) {
1687 this->
write(separator);
1691 this->
write(rightBracket);
1695 const char* leftBracket,
1696 const char* rightBracket,
1703 this->
write(
"float4(_fragCoord.x, ");
1705 this->
write(
".x + ");
1707 this->
write(
".y * _fragCoord.y, 0.0, _fragCoord.w)");
1709 this->
write(
"float4(_fragCoord.x, _fragCoord.y, 0.0, _fragCoord.w)");
1767 this->
write(
"_out.sk_FragColor");
1770 this->
write(
"_out.sk_SampleMask");
1774 this->
write(
"_out.sk_SecondaryFragColor");
1783 this->
write(
"sk_SampleMaskIn");
1786 this->
write(
"sk_VertexID");
1789 this->
write(
"sk_InstanceID");
1797 this->
write(
"_frontFacing");
1811 this->
write(
"_in.");
1813 this->
write(
"_out.");
1815 this->
write(
"_uniforms.");
1817 this->
write(
"_threadgroups.");
1819 this->
write(
"_globals.");
1830 this->
write(*existing);
1839 this->
write(scratchVar);
1843 this->
write(scratchVar);
1867 for (int8_t component : swizzle.
components()) {
1868 this->
write(separator());
1883 const Field* field = &
f.base()->type().fields()[
f.fieldIndex()];
1890 this->
write(
"_out.sk_Position");
1893 this->
write(
"_out.sk_PointSize");
1896 if (FieldAccess::OwnerKind::kAnonymousInterfaceBlock ==
f.ownerKind()) {
1897 this->
write(
"_globals.");
1922 " left = left * right;\n"
1933 SkASSERT(left.rows() == right.rows());
1934 SkASSERT(left.columns() == right.columns());
1941thread bool operator==(const %s left, const %s right);
1942thread bool operator!=(const %s left, const %s right);
1950 "thread bool operator==(const %s left, const %s right) {\n"
1954 const char* separator =
"";
1955 for (
int index=0; index<left.columns(); ++index) {
1957 separator =
" &&\n ";
1963 "thread bool operator!=(const %s left, const %s right) {\n"
1964 " return !(left == right);\n"
1973 std::string
key =
"Matrix / " + this->
typeName(type);
1980 "thread %s operator/(const %s left, const %s right) {\n"
1984 const char* separator =
"";
1985 for (
int index=0; index<
type.columns(); ++index) {
1992 "thread %s& operator/=(thread %s& left, thread const %s& right) {\n"
1993 " left = left / right;\n"
2006 std::string
key =
"ArrayEquality []";
2010template <typename T1, typename T2>
2011bool operator==(const array_ref<T1> left, const array_ref<T2> right);
2012template <typename T1, typename T2>
2013bool operator!=(const array_ref<T1> left, const array_ref<T2> right);
2016template <typename T1, typename T2>
2017bool operator==(const array_ref<T1> left, const array_ref<T2> right) {
2018 if (left.size() != right.size()) {
2021 for (size_t index = 0; index < left.size(); ++index) {
2022 if (!all(left[index] == right[index])) {
2029template <typename T1, typename T2>
2030bool operator!=(const array_ref<T1> left, const array_ref<T2> right) {
2031 return !(left == right);
2039 std::string
key =
"StructEquality " + this->
typeName(type);
2044 for (
const Field& field :
type.fields()) {
2051thread bool operator==(thread const %s& left, thread const %s& right);
2052thread bool operator!=(thread const %s& left, thread const %s& right);
2060 "thread bool operator==(thread const %s& left, thread const %s& right) {\n"
2065 const char* separator =
"";
2066 for (
const Field& field :
type.fields()) {
2067 if (field.fType->isArray()) {
2069 "%s(make_array_ref(left.%.*s) == make_array_ref(right.%.*s))",
2071 (
int)field.fName.size(), field.fName.data(),
2072 (
int)field.fName.size(), field.fName.data());
2076 (
int)field.fName.size(), field.fName.data(),
2077 (
int)field.fName.size(), field.fName.data());
2079 separator =
" &&\n ";
2084 "thread bool operator!=(thread const %s& left, thread const %s& right) {\n"
2085 " return !(left == right);\n"
2108 std::string str = this->
typeName(type) +
'(';
2111 for (
int index =
type.slotCount(); index--;) {
2138 if (needMatrixSplatOnScalar) {
2141 this->
write(
"make_array_ref(");
2153 const Type& leftType = left.type();
2154 const Type& rightType = right.type();
2157 bool needParens = precedence >= parentPrecedence;
2158 switch (op.
kind()) {
2159 case Operator::Kind::EQEQ:
2166 case Operator::Kind::NEQ:
2226 if (Precedence::kTernary >= parentPrecedence) {
2234 if (Precedence::kTernary >= parentPrecedence) {
2242 switch (op.
kind()) {
2249 case Operator::Kind::MINUS:
2251 if (
p.operand()->type().isMatrix()) {
2260 case Operator::Kind::PLUSPLUS:
2261 case Operator::Kind::MINUSMINUS:
2262 if (
p.operand()->type().isMatrix()) {
2267 this->
write(op.
kind() == Operator::Kind::PLUSPLUS ?
" += " :
" -= ");
2278 if (Precedence::kPrefix >= parentPrecedence) {
2285 if (Precedence::kPrefix >= parentPrecedence) {
2293 switch (op.
kind()) {
2294 case Operator::Kind::PLUSPLUS:
2295 case Operator::Kind::MINUSMINUS:
2296 if (
p.operand()->type().isMatrix()) {
2302 this->
write(tempMatrix);
2305 this->
write(
"), (");
2307 this->
write(op.
kind() == Operator::Kind::PLUSPLUS ?
" += " :
" -= ");
2310 this->
write(tempMatrix);
2320 if (Precedence::kPostfix >= parentPrecedence) {
2325 if (Precedence::kPostfix >= parentPrecedence) {
2332 if (
type.isFloat()) {
2356 const char*& separator) {
2359 this->
write(separator);
2364 this->
write(separator);
2365 this->
write(
"_out");
2369 this->
write(separator);
2370 this->
write(
"_uniforms");
2374 this->
write(separator);
2375 this->
write(
"_globals");
2379 this->
write(separator);
2380 this->
write(
"_fragCoord");
2384 this->
write(separator);
2385 this->
write(
"sk_SampleMaskIn");
2389 this->
write(separator);
2390 this->
write(
"sk_VertexID");
2394 this->
write(separator);
2395 this->
write(
"sk_InstanceID");
2399 this->
write(separator);
2400 this->
write(
"_threadgroups");
2406 const char*& separator) {
2409 this->
write(separator);
2410 this->
write(
"Inputs _in");
2414 this->
write(separator);
2415 this->
write(
"thread Outputs& _out");
2419 this->
write(separator);
2420 this->
write(
"Uniforms _uniforms");
2424 this->
write(separator);
2425 this->
write(
"thread Globals& _globals");
2429 this->
write(separator);
2430 this->
write(
"float4 _fragCoord");
2434 this->
write(separator);
2435 this->
write(
"uint sk_SampleMaskIn");
2439 this->
write(separator);
2440 this->
write(
"uint sk_VertexID");
2444 this->
write(separator);
2445 this->
write(
"uint sk_InstanceID");
2449 this->
write(separator);
2450 this->
write(
"threadgroup Threadgroups& _threadgroups");
2461 return (layout.
fSet >= 0) ? layout.
fSet
2469 const char* separator =
"";
2472 this->
write(
"fragment Outputs fragmentMain(");
2474 this->
write(
"vertex Outputs vertexMain(");
2476 this->
write(
"kernel void computeMain(");
2482 this->
write(
"Inputs _in [[stage_in]]");
2486 this->
write(separator);
2487 this->
write(
"constant Uniforms& _uniforms [[buffer(" +
2506 this->
write(separator);
2514 this->
write(
" [[texture(");
2516 this->
write(
")]], sampler ");
2519 this->
write(
" [[sampler(");
2527 this->
write(
" [[texture(");
2532 std::string_view attr;
2535 attr =
" [[threadgroups_per_grid]]";
2538 attr =
" [[threadgroup_position_in_grid]]";
2541 attr =
" [[thread_position_in_threadgroup]]";
2544 attr =
" [[thread_position_in_grid]]";
2547 attr =
" [[thread_index_in_threadgroup]]";
2552 if (!attr.empty()) {
2553 this->
write(separator);
2563 if (intf.
typeName() ==
"sk_PerVertex") {
2566 this->
write(separator);
2568 this->
write(
"const ");
2574 this->
write(
" [[buffer(");
2583 this->
write(separator);
2584 this->
write(
"constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(1)]]");
2588 this->
write(separator);
2589 this->
write(
"bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]");
2591 this->
write(
", uint sk_SampleMaskIn [[sample_mask]]");
2599 this->
write(separator);
2600 this->
write(
"uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
2610 for (
const Variable* param :
f.parameters()) {
2615 if (
f.isMain() && param ==
f.getMainCoordsParameter()) {
2618 this->
write(separator);
2643 for (
int index = block.
size(); index--; ) {
2644 stmt = block[index].get();
2651 if (!stmt->
is<
Nop>()) {
2662 this->
write(
"Inputs _in = { ");
2663 const char* separator =
"";
2669 this->
write(separator);
2709 for (
const std::unique_ptr<Statement>& stmt :
f.body()->as<
Block>().
children()) {
2710 if (!stmt->isEmpty()) {
2732 this->
write(
"device ");
2734 this->
write(
"thread ");
2737 this->
write(
"const ");
2742 if (intf.
typeName() ==
"sk_PerVertex") {
2747 this->
write(
"struct ");
2775 int currentOffset = 0;
2776 for (
const Field& field : fields) {
2777 int fieldOffset = field.fLayout.fOffset;
2778 const Type* fieldType = field.fType;
2781 "' is not permitted here");
2784 if (fieldOffset != -1) {
2785 if (currentOffset > fieldOffset) {
2787 "offset of field '" + std::string(field.fName) +
2790 }
else if (currentOffset < fieldOffset) {
2791 this->
write(
"char pad");
2796 currentOffset = fieldOffset;
2801 "offset of field '" + std::string(field.fName) +
2820 size_t fieldSize = memoryLayout.
size(*fieldType);
2825 currentOffset += fieldSize;
2851 if (varDecl.
value()) {
2860 case Statement::Kind::kBlock:
2863 case Statement::Kind::kExpression:
2866 case Statement::Kind::kReturn:
2869 case Statement::Kind::kVarDeclaration:
2872 case Statement::Kind::kIf:
2875 case Statement::Kind::kFor:
2878 case Statement::Kind::kDo:
2881 case Statement::Kind::kSwitch:
2884 case Statement::Kind::kBreak:
2885 this->
write(
"break;");
2888 this->
write(
"continue;");
2891 this->
write(
"discard_fragment();");
2905 bool isScope =
b.isScope() ||
b.isEmpty();
2910 for (
const std::unique_ptr<Statement>& stmt :
b.children()) {
2911 if (!stmt->isEmpty()) {
2923 this->
write(
"if (");
2928 this->
write(
" else ");
2935 if (!
f.initializer() &&
f.test() && !
f.next()) {
2936 this->
write(
"while (");
2943 this->
write(
"for (");
2963 this->
write(
" while (");
2978 this->
write(
"switch (");
2982 for (
const std::unique_ptr<Statement>& stmt :
s.cases()) {
2987 this->
write(
"case ");
3006 this->
write(
"return _out;");
3008 this->
write(
"return;");
3018 this->
write(
"_out.sk_FragColor = ");
3023 "Metal does not support returning '" +
3024 r.
expression()->type().description() +
"' from main()");
3031 this->
write(
"return");
3040 this->
writeLine(
"#include <metal_stdlib>");
3041 this->
writeLine(
"#include <simd/simd.h>");
3043 this->
writeLine(
"#pragma clang diagnostic ignored \"-Wall\"");
3045 this->
writeLine(
"using namespace metal;");
3051 void visitSampler(
const Type&, std::string_view)
override {
3052 if (fWrotePolyfill) {
3055 fWrotePolyfill =
true;
3059 texture2d<half> tex;
3062half4 sample(sampler2D i, float2 p, float b=%g) { return i.tex.sample(i.smp, p, bias(b)); }
3063half4 sample(sampler2D i, float3 p, float b=%g) { return i.tex.sample(i.smp, p.xy / p.z, bias(b)); }
3064half4 sampleLod(sampler2D i, float2 p, float lod) { return i.tex.sample(i.smp, p, level(lod)); }
3065half4 sampleLod(sampler2D i, float3 p, float lod) {
3066 return i.tex.sample(i.smp, p.xy / p.z, level(lod));
3068half4 sampleGrad(sampler2D i, float2 p, float2 dPdx, float2 dPdy) {
3069 return i.tex.sample(i.smp, p, gradient2d(dPdx, dPdy));
3075 fCodeGen->write(polyfill.c_str());
3079 float fTextureBias = 0.0f;
3080 bool fWrotePolyfill =
false;
3083 visitor.fCodeGen =
this;
3094 if (var.modifierFlags().isUniform()) {
3100 this->
write(
"struct Uniforms {\n");
3104 "Metal backend requires all uniforms to have the same "
3105 "'layout(set=...)'");
3116 this->
write(
"};\n");
3121 this->
write(
"struct Inputs {\n");
3131 this->
write(
"device ");
3139 if (-1 != var.layout().fLocation) {
3152 this->
write(
"};\n");
3156 this->
write(
"struct Outputs {\n");
3158 this->
write(
" float4 sk_Position [[position]];\n");
3160 this->
write(
" half4 sk_FragColor [[color(0)]];\n");
3162 this->
write(
" half4 sk_SecondaryFragColor [[color(0), index(1)]];\n");
3170 this->
write(
" uint sk_SampleMask [[sample_mask]];\n");
3178 this->
write(
"device ");
3188 int location = var.layout().fLocation;
3192 "Metal out variables must have 'layout(location=...)'");
3197 int colorIndex = var.layout().fIndex;
3208 this->
write(
" float sk_PointSize [[point_size]];\n");
3210 this->
write(
"};\n");
3214 bool wroteInterfaceBlock =
false;
3218 wroteInterfaceBlock =
true;
3221 if (!wroteInterfaceBlock &&
3223 this->
writeLine(
"struct sksl_synthetic_uniforms {");
3240 void visitConstantVariable(
const VarDeclaration& decl)
override {
3241 fCodeGen->write(
"constant ");
3242 fCodeGen->writeVarDeclaration(decl);
3243 fCodeGen->finishLine();
3249 visitor.fCodeGen =
this;
3257 if (ib->typeName() !=
"sk_PerVertex") {
3293 std::string_view blockName)
override {
3295 fCodeGen->write(
" ");
3297 fCodeGen->write(
"const ");
3299 fCodeGen->write(
is_buffer(block) ?
"device " :
"constant ");
3301 fCodeGen->write(
"* ");
3302 fCodeGen->writeName(blockName);
3303 fCodeGen->write(
";\n");
3305 void visitTexture(
const Type&
type, std::string_view
name)
override {
3307 fCodeGen->write(
" ");
3308 fCodeGen->writeType(
type);
3309 fCodeGen->write(
" ");
3310 fCodeGen->writeName(
name);
3311 fCodeGen->write(
";\n");
3313 void visitSampler(
const Type&, std::string_view
name)
override {
3315 fCodeGen->write(
" sampler2D ");
3316 fCodeGen->writeName(
name);
3317 fCodeGen->write(
";\n");
3319 void visitConstantVariable(
const VarDeclaration& decl)
override {
3324 fCodeGen->write(
" ");
3326 fCodeGen->writeType(var.
type());
3327 fCodeGen->write(
" ");
3329 fCodeGen->write(
";\n");
3333 fCodeGen->write(
"struct Globals {\n");
3339 fCodeGen->writeLine(
"};");
3348 visitor.fCodeGen =
this;
3357 std::string_view blockName)
override {
3359 fCodeGen->write(
"&");
3360 fCodeGen->writeName(blockName);
3362 void visitTexture(
const Type&, std::string_view
name)
override {
3364 fCodeGen->writeName(
name);
3366 void visitSampler(
const Type&, std::string_view
name)
override {
3368 fCodeGen->write(
"{");
3369 fCodeGen->writeName(
name);
3371 fCodeGen->write(
", ");
3372 fCodeGen->writeName(
name);
3374 fCodeGen->write(
"}");
3376 void visitConstantVariable(
const VarDeclaration& decl)
override {
3382 fCodeGen->writeVarInitializer(var, *
value);
3384 fCodeGen->write(
"{}");
3389 fCodeGen->write(
"Globals _globals{");
3392 fCodeGen->write(
", ");
3397 fCodeGen->writeLine(
"};");
3398 fCodeGen->writeLine(
"(void)_globals;");
3405 visitor.fCodeGen =
this;
3429 void visitNonconstantVariable(
const Variable& var)
override {
3431 fCodeGen->write(
" ");
3433 fCodeGen->writeType(var.
type());
3434 fCodeGen->write(
" ");
3436 fCodeGen->write(
";\n");
3440 fCodeGen->write(
"struct Threadgroups {\n");
3446 fCodeGen->writeLine(
"};");
3455 visitor.fCodeGen =
this;
3463 void visitNonconstantVariable(
const Variable& var)
override {
3465 fCodeGen->write(
"{}");
3469 fCodeGen->write(
"threadgroup Threadgroups _threadgroups{");
3472 fCodeGen->write(
", ");
3477 fCodeGen->writeLine(
"};");
3478 fCodeGen->writeLine(
"(void)_threadgroups;");
3485 visitor.fCodeGen =
this;
3494 case ProgramElement::Kind::kGlobalVar:
3496 case ProgramElement::Kind::kInterfaceBlock:
3499 case ProgramElement::Kind::kStructDefinition:
3505 case ProgramElement::Kind::kFunctionPrototype:
3508 case ProgramElement::Kind::kModifiers:
3512 SkDEBUGFAILF(
"unsupported program element: %s\n",
e.description().c_str());
3522 bool visitExpression(
const Expression&
e)
override {
3524 case Expression::Kind::kFunctionCall: {
3529 case Expression::Kind::kFieldAccess: {
3531 if (
f.ownerKind() == FieldAccess::OwnerKind::kAnonymousInterfaceBlock) {
3537 case Expression::Kind::kVariableReference: {
3568 return INHERITED::visitExpression(
e);
3576 RequirementsVisitor visitor;
3578 visitor.fCodeGen =
this;
3579 visitor.visitStatement(*
s);
3581 return visitor.fRequirements;
3600 if (
f.intrinsicKind() == IntrinsicKind::k_loadFloatBuffer_IntrinsicKind) {
3660 program.
fContext->fErrors->setSource(std::string_view());
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
#define SkDEBUGFAILF(fmt,...)
#define SkASSERTF(cond, fmt,...)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
constexpr int SK_SAMPLEMASK_BUILTIN
constexpr int SK_WORKGROUPID_BUILTIN
constexpr int SK_CLOCKWISE_BUILTIN
constexpr int SK_VERTEXID_BUILTIN
constexpr int SK_FRAGCOLOR_BUILTIN
constexpr int SK_LASTFRAGCOLOR_BUILTIN
constexpr int SK_GLOBALINVOCATIONID_BUILTIN
constexpr int SK_POSITION_BUILTIN
constexpr int SK_LOCALINVOCATIONID_BUILTIN
constexpr int SK_INSTANCEID_BUILTIN
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
constexpr int SK_NUMWORKGROUPS_BUILTIN
constexpr int SK_POINTSIZE_BUILTIN
constexpr int SK_FRAGCOORD_BUILTIN
constexpr int SK_LOCALINVOCATIONINDEX_BUILTIN
constexpr int SK_SAMPLEMASKIN_BUILTIN
constexpr size_t SkToSizeT(S x)
virtual SkSpan< std::unique_ptr< Expression > > argumentSpan()=0
const StatementArray & children() const
const std::unique_ptr< Type > fHalf4
const std::unique_ptr< Type > fUShort
const std::unique_ptr< Type > fAtomicUInt
const std::unique_ptr< Type > fUInt
static constexpr float kSharpenTexturesBias
CodeGenerator(const Context *context, const ShaderCaps *caps, const Program *program, OutputStream *stream)
const BuiltinTypes & fTypes
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & statement()
void error(Position position, std::string_view msg)
ExpressionArray clone() const
const std::unique_ptr< Expression > & expression() const
const Type & type() const
std::string description() const final
AnyConstructor & asAnyConstructor()
std::unique_ptr< Expression > & base()
std::unique_ptr< Statement > & statement()
std::unique_ptr< Expression > & next()
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & initializer()
ExpressionArray & arguments()
const FunctionDeclaration & function() const
std::string mangledName() const
const Type & returnType() const
std::unique_ptr< Statement > & body()
const FunctionDeclaration & declaration() const
const FunctionDeclaration & declaration() const
VarDeclaration & varDeclaration()
Position position() const
virtual std::string description() const =0
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & ifTrue()
std::unique_ptr< Statement > & ifFalse()
std::unique_ptr< Expression > & base()
std::unique_ptr< Expression > & index()
std::string_view instanceName() const
std::string_view typeName() const
std::string description(OperatorPrecedence) const override
SKSL_INT intValue() const
size_t size(const Type &type) const
size_t isSupported(const Type &type) const
size_t alignment(const Type &type) const
ExpressionArray & arguments()
SkSpan< std::unique_ptr< Expression > > argumentSpan() final
std::string_view tightOperatorName() const
OperatorPrecedence getBinaryPrecedence() const
const char * operatorName() const
Operator removeAssignment() const
bool isCompoundAssignment() const
bool isValidForMatrixOrVector() const
void printf(const char format[],...) SK_PRINTF_LIKE(2
virtual void writeText(const char *s)=0
std::unique_ptr< Expression > & operand()
std::unique_ptr< Expression > & operand()
std::unique_ptr< Expression > & expression()
std::unique_ptr< Expression > toLiteral(const ShaderCaps &caps) const
std::unique_ptr< Expression > & argument()
void write8(uint8_t b) override
void writeText(const char *s) override
const std::string & str() const
std::unique_ptr< Statement > & statement()
std::unique_ptr< Expression > & value()
std::unique_ptr< Expression > & base()
const ComponentArray & components() const
static std::string MaskString(const ComponentArray &inComponents)
std::string_view name() const
const Type & type() const
virtual bool visitStatement(typename T::Statement &statement)
std::unique_ptr< Expression > & ifTrue()
std::unique_ptr< Expression > & test()
std::unique_ptr< Expression > & ifFalse()
virtual bool isArray() const
bool highPrecision() const
virtual bool isVector() const
virtual const Type & componentType() const
virtual SkSpan< const Field > fields() const
bool matches(const Type &other) const
virtual bool isMatrix() const
virtual const Type & resolve() const
virtual const Type & textureType() const
virtual int columns() const
virtual bool isScalar() const
virtual const Type & scalarTypeForLiteral() const
virtual bool isUnsizedArray() const
const Type & columnType(const Context &context) const
std::string displayName() const
TypeKind typeKind() const
virtual bool isStruct() const
virtual SpvDim_ dimensions() const
std::unique_ptr< Expression > & value()
const Variable * variable() const
virtual std::string_view mangledName() const
ModifierFlags modifierFlags() const
virtual const Layout & layout() const
constexpr size_t size() const
bool contains(const T &item) const
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
EMSCRIPTEN_KEEPALIVE void empty()
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Dart_NativeFunction function
static float max(float r, float g, float b)
bool IsTrivialExpression(const Expression &expr)
bool HasSideEffects(const Expression &expr)
bool IsAssignable(Expression &expr, AssignmentInfo *info=nullptr, ErrorReporter *errors=nullptr)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
std::string void void auto Separator()
std::string void appendf(std::string *str, const char *fmt,...) SK_PRINTF_LIKE(2
static bool is_uniforms(const Variable &var)
static constexpr char kInverse3x3[]
static bool is_buffer(const InterfaceBlock &block)
static constexpr char kInverse2x2[]
void write_stringstream(const StringStream &s, OutputStream &out)
static bool is_in_globals(const Variable &var)
static constexpr char kInverse4x4[]
static bool is_input(const Variable &var)
static bool is_readonly(const InterfaceBlock &block)
static bool is_block_ending_with_return(const Statement *stmt)
static bool is_threadgroup(const Variable &var)
bool ToMetal(Program &program, const ShaderCaps *caps, OutputStream &out)
static bool pass_by_reference(const Type &type, ModifierFlags flags)
static const char * operator_name(Operator op)
static bool is_output(const Variable &var)
static bool is_compute_builtin(const Variable &var)
static bool needs_address_space(const Type &type, ModifierFlags modifiers)
DEF_SWITCHES_START aot vmservice shared library name
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
static SkString to_string(int n)
static const char header[]
static std::unique_ptr< Expression > LoadFloatBuffer(const Context &context, const SkSL::ShaderCaps &shaderCaps, Position position, std::unique_ptr< Expression > idx)
static bool IsVertex(ProgramKind kind)
static bool IsFragment(ProgramKind kind)
static bool IsCompute(ProgramKind kind)
bool fOutputSecondaryColor
ElementsCollection elements() const
std::shared_ptr< Context > fContext
ProgramInterface fInterface
std::vector< const ProgramElement * > fSharedElements
std::unique_ptr< std::string > fSource
std::unique_ptr< ProgramConfig > fConfig
bool fDualSourceBlendingSupport
const char * fFBFetchColorName
#define TRACE_EVENT0(category_group, name)