81#include <initializer_list>
100 ,
fReservedWords({
"atan2",
"rsqrt",
"rint",
"dfdx",
"dfdy",
"vertex",
"fragment"})
126 void write(std::string_view
s);
128 void writeLine(std::string_view
s = std::string_view());
175 const char*& separator);
250 const char* leftBracket,
251 const char* rightBracket,
255 const char* leftBracket,
256 const char* rightBracket,
370 case Operator::Kind::LOGICALXOR:
return " != ";
395#if defined(SK_DEBUG) || defined(SKSL_STANDALONE)
419 this->
writeLine(
"#extension " + std::string(ext.name()) +
" : enable");
425 switch (
type.typeKind()) {
428 SkASSERTF(
type.columns() > 0,
"invalid array size: %s",
type.description().c_str());
437 std::to_string(
type.rows());
446 switch (
type.textureAccess()) {
458 return "atomic_uint";
461 return std::string(
type.name());
479 switch (expr.
kind()) {
480 case Expression::Kind::kBinary:
483 case Expression::Kind::kConstructorArray:
484 case Expression::Kind::kConstructorStruct:
487 case Expression::Kind::kConstructorArrayCast:
490 case Expression::Kind::kConstructorCompound:
493 case Expression::Kind::kConstructorDiagonalMatrix:
494 case Expression::Kind::kConstructorSplat:
497 case Expression::Kind::kConstructorMatrixResize:
501 case Expression::Kind::kConstructorScalarCast:
502 case Expression::Kind::kConstructorCompoundCast:
505 case Expression::Kind::kEmpty:
506 this->
write(
"false");
508 case Expression::Kind::kFieldAccess:
511 case Expression::Kind::kLiteral:
514 case Expression::Kind::kFunctionCall:
517 case Expression::Kind::kPrefix:
520 case Expression::Kind::kPostfix:
523 case Expression::Kind::kSetting:
526 case Expression::Kind::kSwizzle:
529 case Expression::Kind::kVariableReference:
532 case Expression::Kind::kTernary:
535 case Expression::Kind::kIndex:
569 auto oldIndexSubstitutionData = std::make_unique<IndexSubstitutionData>();
611 bool foundOutParam =
false;
615 for (
int index = 0; index < arguments.
size(); ++index) {
623 foundOutParam =
true;
648 std::string scratchResultName;
649 if (!
function.returnType().isVoid()) {
651 this->
write(scratchResultName);
660 const char* separator =
"";
663 for (
int i = 0; i < arguments.
size(); ++i) {
664 this->
write(separator);
672 this->
write(scratchVarName[i]);
678 this->
write(scratchVarName[i]);
690 for (
int i = 0; i < arguments.
size(); ++i) {
691 if (!scratchVarName[i].
empty()) {
695 this->
write(scratchVarName[i]);
702 if (!scratchResultName.empty()) {
704 this->
write(scratchResultName);
715 const char* separator =
"";
717 for (
int i = 0; i < arguments.
size(); ++i) {
719 this->
write(separator);
729matrix<T, 2, 2> mat2_inverse(matrix<T, 2, 2> m) {
730return matrix<T, 2, 2>(m[1].y, -m[0].y, -m[1].x, m[0].x) * (1/determinant(m));
736matrix<T, 3, 3> mat3_inverse(matrix<T, 3, 3> m) {
738 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z,
739 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z,
740 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z,
741 b01 = a22*a11 - a12*a21,
742 b11 = -a22*a10 + a12*a20,
743 b21 = a21*a10 - a11*a20,
744 det = a00*b01 + a01*b11 + a02*b21;
745return matrix<T, 3, 3>(
746 b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11),
747 b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10),
748 b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) * (1/det);
754matrix<T, 4, 4> mat4_inverse(matrix<T, 4, 4> m) {
756 a00 = m[0].x, a01 = m[0].y, a02 = m[0].z, a03 = m[0].w,
757 a10 = m[1].x, a11 = m[1].y, a12 = m[1].z, a13 = m[1].w,
758 a20 = m[2].x, a21 = m[2].y, a22 = m[2].z, a23 = m[2].w,
759 a30 = m[3].x, a31 = m[3].y, a32 = m[3].z, a33 = m[3].w,
760 b00 = a00*a11 - a01*a10,
761 b01 = a00*a12 - a02*a10,
762 b02 = a00*a13 - a03*a10,
763 b03 = a01*a12 - a02*a11,
764 b04 = a01*a13 - a03*a11,
765 b05 = a02*a13 - a03*a12,
766 b06 = a20*a31 - a21*a30,
767 b07 = a20*a32 - a22*a30,
768 b08 = a20*a33 - a23*a30,
769 b09 = a21*a32 - a22*a31,
770 b10 = a21*a33 - a23*a31,
771 b11 = a22*a33 - a23*a32,
772 det = b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06;
773return matrix<T, 4, 4>(
774 a11*b11 - a12*b10 + a13*b09,
775 a02*b10 - a01*b11 - a03*b09,
776 a31*b05 - a32*b04 + a33*b03,
777 a22*b04 - a21*b05 - a23*b03,
778 a12*b08 - a10*b11 - a13*b07,
779 a00*b11 - a02*b08 + a03*b07,
780 a32*b02 - a30*b05 - a33*b01,
781 a20*b05 - a22*b02 + a23*b01,
782 a10*b10 - a11*b08 + a13*b06,
783 a01*b08 - a00*b10 - a03*b06,
784 a30*b04 - a31*b02 + a33*b00,
785 a21*b02 - a20*b04 - a23*b00,
786 a11*b07 - a10*b09 - a12*b06,
787 a00*b09 - a01*b07 + a02*b06,
788 a31*b01 - a30*b03 - a32*b00,
789 a20*b03 - a21*b01 + a22*b00) * (1/det);
798 switch (
type.rows()) {
804 return "mat2_inverse";
810 return "mat3_inverse";
816 return "mat4_inverse";
824 static constexpr char kMatrixCompMult[] = R
"(
825template <typename T, int C, int R>
826matrix<T, C, R> matrixCompMult(matrix<T, C, R> a, const matrix<T, C, R> b) {
827 for (int c = 0; c < C; ++c) { a[c] *= b[c]; }
838 static constexpr char kOuterProduct[] = R
"(
839template <typename T, int C, int R>
840matrix<T, C, R> outerProduct(const vec<T, R> a, const vec<T, C> b) {
842 for (int c = 0; c < C; ++c) { m[c] = a * b[c]; }
853 std::string tempVar =
"_skTemp" + std::to_string(
fVarCount++);
866 const char* separator =
"";
867 for (
const std::unique_ptr<Expression>& arg : arguments) {
868 this->
write(separator);
878 case k_textureRead_IntrinsicKind: {
880 this->
write(
".read(");
885 case k_textureWrite_IntrinsicKind: {
887 this->
write(
".write(");
894 case k_textureWidth_IntrinsicKind: {
896 this->
write(
".get_width()");
899 case k_textureHeight_IntrinsicKind: {
901 this->
write(
".get_height()");
904 case k_mod_IntrinsicKind: {
908 this->
write(
"(" + tmpX +
" = ");
910 this->
write(
", " + tmpY +
" = ");
912 this->
write(
", " + tmpX +
" - " + tmpY +
" * floor(" + tmpX +
" / " + tmpY +
"))");
916 case k_distance_IntrinsicKind: {
917 if (arguments[0]->
type().columns() == 1) {
928 case k_dot_IntrinsicKind: {
929 if (arguments[0]->
type().columns() == 1) {
940 case k_faceforward_IntrinsicKind: {
941 if (arguments[0]->
type().columns() == 1) {
945 this->
write(
") * (");
947 this->
write(
") < 0) ? 1 : -1) * (");
955 case k_length_IntrinsicKind: {
956 this->
write(arguments[0]->
type().columns() == 1 ?
"abs(" :
"length(");
961 case k_normalize_IntrinsicKind: {
962 this->
write(arguments[0]->
type().columns() == 1 ?
"sign(" :
"normalize(");
967 case k_packUnorm2x16_IntrinsicKind: {
968 this->
write(
"pack_float_to_unorm2x16(");
973 case k_unpackUnorm2x16_IntrinsicKind: {
974 this->
write(
"unpack_unorm2x16_to_float(");
979 case k_packSnorm2x16_IntrinsicKind: {
980 this->
write(
"pack_float_to_snorm2x16(");
985 case k_unpackSnorm2x16_IntrinsicKind: {
986 this->
write(
"unpack_snorm2x16_to_float(");
991 case k_packUnorm4x8_IntrinsicKind: {
992 this->
write(
"pack_float_to_unorm4x8(");
997 case k_unpackUnorm4x8_IntrinsicKind: {
998 this->
write(
"unpack_unorm4x8_to_float(");
1003 case k_packSnorm4x8_IntrinsicKind: {
1004 this->
write(
"pack_float_to_snorm4x8(");
1009 case k_unpackSnorm4x8_IntrinsicKind: {
1010 this->
write(
"unpack_snorm4x8_to_float(");
1015 case k_packHalf2x16_IntrinsicKind: {
1016 this->
write(
"as_type<uint>(half2(");
1021 case k_unpackHalf2x16_IntrinsicKind: {
1022 this->
write(
"float2(as_type<half2>(");
1027 case k_floatBitsToInt_IntrinsicKind:
1028 case k_floatBitsToUint_IntrinsicKind:
1029 case k_intBitsToFloat_IntrinsicKind:
1030 case k_uintBitsToFloat_IntrinsicKind: {
1037 case k_degrees_IntrinsicKind: {
1040 this->
write(
") * 57.2957795)");
1043 case k_radians_IntrinsicKind: {
1046 this->
write(
") * 0.0174532925)");
1049 case k_dFdx_IntrinsicKind: {
1050 this->
write(
"dfdx");
1054 case k_dFdy_IntrinsicKind: {
1058 this->
write(
"(dfdy");
1064 case k_inverse_IntrinsicKind: {
1069 case k_inversesqrt_IntrinsicKind: {
1070 this->
write(
"rsqrt");
1074 case k_atan_IntrinsicKind: {
1079 case k_reflect_IntrinsicKind: {
1080 if (arguments[0]->
type().columns() == 1) {
1086 this->
write(
"(" + tmpI +
" = ");
1090 this->
write(
", " + tmpN +
" = ");
1094 this->
write(
", " + tmpI +
" - 2 * " + tmpN +
" * " + tmpI +
" * " + tmpN +
")");
1100 case k_refract_IntrinsicKind: {
1101 if (arguments[0]->
type().columns() == 1) {
1104 this->
write(
"(refract(float2(");
1106 this->
write(
", 0), float2(");
1108 this->
write(
", 0), ");
1110 this->
write(
").x)");
1116 case k_roundEven_IntrinsicKind: {
1117 this->
write(
"rint");
1121 case k_bitCount_IntrinsicKind: {
1122 this->
write(
"popcount(");
1127 case k_findLSB_IntrinsicKind: {
1130 std::string exprType = this->
typeName(arguments[0]->
type());
1137 this->
write(skTemp);
1138 this->
write(
" = (");
1140 this->
write(
"), select(ctz(");
1141 this->
write(skTemp);
1143 this->
write(exprType);
1144 this->
write(
"(-1), ");
1145 this->
write(skTemp);
1146 this->
write(
" == ");
1147 this->
write(exprType);
1148 this->
write(
"(0)))");
1151 case k_findMSB_IntrinsicKind: {
1154 std::string exprType = this->
typeName(arguments[0]->
type());
1162 this->
write(skTemp1);
1163 this->
write(
" = (");
1169 std::string skTemp2;
1170 if (arguments[0]->
type().isSigned()) {
1173 this->
write(skTemp2);
1174 this->
write(
" = (select(");
1175 this->
write(skTemp1);
1177 this->
write(skTemp1);
1179 this->
write(skTemp1);
1180 this->
write(
" < 0)), ");
1186 this->
write(
"select(");
1188 this->
write(
"(clz(");
1189 this->
write(skTemp2);
1190 this->
write(
")), ");
1192 this->
write(
"(-1), ");
1193 this->
write(skTemp2);
1194 this->
write(
" == ");
1195 this->
write(exprType);
1196 this->
write(
"(0)))");
1199 case k_sign_IntrinsicKind: {
1200 if (arguments[0]->
type().componentType().isInteger()) {
1203 std::string exprType = this->
typeName(arguments[0]->
type());
1207 this->
write(skTemp);
1208 this->
write(
" = (");
1213 this->
write(
"select(select(");
1214 this->
write(exprType);
1215 this->
write(
"(0), ");
1216 this->
write(exprType);
1217 this->
write(
"(-1), ");
1218 this->
write(skTemp);
1219 this->
write(
" < 0), ");
1220 this->
write(exprType);
1221 this->
write(
"(1), ");
1222 this->
write(skTemp);
1223 this->
write(
" > 0))");
1229 case k_matrixCompMult_IntrinsicKind: {
1234 case k_outerProduct_IntrinsicKind: {
1239 case k_mix_IntrinsicKind: {
1241 if (arguments[2]->
type().componentType().isBoolean()) {
1243 this->
write(
"select");
1251 case k_equal_IntrinsicKind:
1252 case k_greaterThan_IntrinsicKind:
1253 case k_greaterThanEqual_IntrinsicKind:
1254 case k_lessThan_IntrinsicKind:
1255 case k_lessThanEqual_IntrinsicKind:
1256 case k_notEqual_IntrinsicKind: {
1260 case k_equal_IntrinsicKind:
1261 this->
write(
" == ");
1263 case k_notEqual_IntrinsicKind:
1264 this->
write(
" != ");
1266 case k_lessThan_IntrinsicKind:
1269 case k_lessThanEqual_IntrinsicKind:
1270 this->
write(
" <= ");
1272 case k_greaterThan_IntrinsicKind:
1275 case k_greaterThanEqual_IntrinsicKind:
1276 this->
write(
" >= ");
1279 SK_ABORT(
"unsupported comparison intrinsic kind");
1285 case k_storageBarrier_IntrinsicKind:
1286 this->
write(
"threadgroup_barrier(mem_flags::mem_device)");
1288 case k_workgroupBarrier_IntrinsicKind:
1289 this->
write(
"threadgroup_barrier(mem_flags::mem_threadgroup)");
1291 case k_atomicAdd_IntrinsicKind:
1292 this->
write(
"atomic_fetch_add_explicit(&");
1296 this->
write(
", memory_order_relaxed)");
1298 case k_atomicLoad_IntrinsicKind:
1299 this->
write(
"atomic_load_explicit(&");
1301 this->
write(
", memory_order_relaxed)");
1303 case k_atomicStore_IntrinsicKind:
1304 this->
write(
"atomic_store_explicit(&");
1308 this->
write(
", memory_order_relaxed)");
1323 const char* separator =
"";
1324 for (
int c = 0; c < columns; ++c) {
1329 int swizzleLength = 0;
1330 if (c < sourceMatrix.
columns()) {
1331 swizzleLength = std::min<>(rows, sourceMatrix.
rows());
1336 switch (swizzleLength) {
1337 case 0: firstItem =
true;
break;
1346 for (
int r = swizzleLength; r < rows; ++r) {
1364 size_t argIndex = 0;
1365 int argPosition = 0;
1368 static constexpr char kSwizzle[] =
"xyzw";
1369 const char* separator =
"";
1370 for (
int c = 0; c < columns; ++c) {
1374 const char* columnSeparator =
"";
1375 for (
int r = 0; r < rows;) {
1377 columnSeparator =
", ";
1379 if (argIndex <
args.size()) {
1380 const Type& argType =
args[argIndex]->type();
1394 }
while (r < rows && argPosition < argType.
columns());
1403 }
while (r < rows && (argPosition % argType.
rows()) != 0);
1407 SkDEBUGFAIL(
"incorrect type of argument for matrix constructor");
1413 if (argPosition >= argType.
columns() * argType.
rows()) {
1418 SkDEBUGFAIL(
"not enough arguments for matrix constructor");
1424 if (argPosition != 0 || argIndex !=
args.size()) {
1425 SkDEBUGFAIL(
"incorrect number of arguments for matrix constructor");
1439 int rows =
type.rows();
1445 for (
const std::unique_ptr<Expression>& expr :
args) {
1458 size_t argIndex = 0;
1459 const char* argSeparator =
"";
1460 for (
const std::unique_ptr<Expression>& expr :
args) {
1462 this->
typeName(expr->type()).c_str(), argIndex++);
1463 argSeparator =
", ";
1468 if (
args.size() == 1 &&
args.front()->type().isMatrix()) {
1504 for (
const std::unique_ptr<Expression>& expr : c.
arguments()) {
1506 if (expr->type().isMatrix()) {
1509 position += expr->type().columns();
1546 const Type& inType = c.
argument()->type().componentType();
1548 std::string inTypeName = this->
typeName(inType);
1549 std::string outTypeName = this->
typeName(outType);
1551 std::string
name =
"array_of_" + outTypeName +
"_from_" + inTypeName;
1556array<%s, N> %s(thread const array<%s, N>& x) {
1557 array<%s, N> result;
1558 for (int i = 0; i < N; ++i) {
1559 result[i] = %s(x[i]);
1564 outTypeName.c_str(), name.c_str(), inTypeName.c_str(),
1565 outTypeName.c_str(),
1566 outTypeName.c_str());
1581 std::string
name =
String::printf(
"%s4_from_%s2x2", baseType.c_str(), baseType.c_str());
1587 return %s4(x[0].xy, x[1].xy);
1589)", baseType.c_str(), name.c_str(), baseType.c_str(), baseType.c_str());
1623 const char* separator =
"";
1624 for (
const std::unique_ptr<Expression>& expr : c.
arguments()) {
1625 this->
write(separator);
1642 const char* separator =
"";
1643 int scalarCount = 0;
1644 for (
const std::unique_ptr<Expression>& arg : c.
arguments()) {
1645 this->
write(separator);
1647 if (arg->type().columns() < matrixType.
rows()) {
1653 scalarCount += arg->type().columns();
1656 if (scalarCount && scalarCount == matrixType.
rows()) {
1666 const char* leftBracket,
1667 const char* rightBracket,
1670 this->
write(leftBracket);
1671 const char* separator =
"";
1672 for (
const std::unique_ptr<Expression>& arg : c.
argumentSpan()) {
1673 this->
write(separator);
1677 this->
write(rightBracket);
1681 const char* leftBracket,
1682 const char* rightBracket,
1689 this->
write(
"float4(_fragCoord.x, ");
1691 this->
write(
".x + ");
1693 this->
write(
".y * _fragCoord.y, 0.0, _fragCoord.w)");
1695 this->
write(
"float4(_fragCoord.x, _fragCoord.y, 0.0, _fragCoord.w)");
1753 this->
write(
"_out.sk_FragColor");
1756 this->
write(
"_out.sk_SampleMask");
1760 this->
write(
"_out.sk_SecondaryFragColor");
1769 this->
write(
"sk_SampleMaskIn");
1772 this->
write(
"sk_VertexID");
1775 this->
write(
"sk_InstanceID");
1783 this->
write(
"_frontFacing");
1795 if (var.
storage() == Variable::Storage::kGlobal) {
1797 this->
write(
"_in.");
1799 this->
write(
"_out.");
1801 this->
write(
"_uniforms.");
1803 this->
write(
"_threadgroups.");
1805 this->
write(
"_globals.");
1816 this->
write(*existing);
1825 this->
write(scratchVar);
1829 this->
write(scratchVar);
1853 for (int8_t component : swizzle.
components()) {
1854 this->
write(separator());
1855 this->
write(std::to_string(component));
1869 const Field* field = &f.base()->type().fields()[f.fieldIndex()];
1870 if (FieldAccess::OwnerKind::kDefault == f.ownerKind()) {
1876 this->
write(
"_out.sk_Position");
1879 this->
write(
"_out.sk_PointSize");
1882 if (FieldAccess::OwnerKind::kAnonymousInterfaceBlock == f.ownerKind()) {
1883 this->
write(
"_globals.");
1908 " left = left * right;\n"
1927thread bool operator==(const %s left, const %s right);
1928thread bool operator!=(const %s left, const %s right);
1936 "thread bool operator==(const %s left, const %s right) {\n"
1940 const char* separator =
"";
1941 for (
int index=0; index<
left.columns(); ++index) {
1943 separator =
" &&\n ";
1949 "thread bool operator!=(const %s left, const %s right) {\n"
1950 " return !(left == right);\n"
1959 std::string
key =
"Matrix / " + this->
typeName(type);
1966 "thread %s operator/(const %s left, const %s right) {\n"
1970 const char* separator =
"";
1971 for (
int index=0; index<
type.columns(); ++index) {
1978 "thread %s& operator/=(thread %s& left, thread const %s& right) {\n"
1979 " left = left / right;\n"
1992 std::string
key =
"ArrayEquality []";
1996template <typename T1, typename T2>
1997bool operator==(const array_ref<T1> left, const array_ref<T2> right);
1998template <typename T1, typename T2>
1999bool operator!=(const array_ref<T1> left, const array_ref<T2> right);
2002template <typename T1, typename T2>
2003bool operator==(const array_ref<T1> left, const array_ref<T2> right) {
2004 if (left.size() != right.size()) {
2007 for (size_t index = 0; index < left.size(); ++index) {
2008 if (!all(left[index] == right[index])) {
2015template <typename T1, typename T2>
2016bool operator!=(const array_ref<T1> left, const array_ref<T2> right) {
2017 return !(left == right);
2025 std::string
key =
"StructEquality " + this->
typeName(type);
2030 for (
const Field& field :
type.fields()) {
2037thread bool operator==(thread const %s& left, thread const %s& right);
2038thread bool operator!=(thread const %s& left, thread const %s& right);
2046 "thread bool operator==(thread const %s& left, thread const %s& right) {\n"
2051 const char* separator =
"";
2052 for (
const Field& field :
type.fields()) {
2053 if (field.fType->isArray()) {
2055 "%s(make_array_ref(left.%.*s) == make_array_ref(right.%.*s))",
2057 (
int)field.fName.size(), field.fName.data(),
2058 (
int)field.fName.size(), field.fName.data());
2062 (
int)field.fName.size(), field.fName.data(),
2063 (
int)field.fName.size(), field.fName.data());
2065 separator =
" &&\n ";
2070 "thread bool operator!=(thread const %s& left, thread const %s& right) {\n"
2071 " return !(left == right);\n"
2102 const char* separator =
"";
2103 for (
int index = matrixType.
slotCount(); index--;) {
2104 this->
write(separator);
2109 this->
write(
") * ");
2121 if (needMatrixSplatOnScalar) {
2124 this->
write(
"make_array_ref(");
2136 const Type& leftType =
left.type();
2140 bool needParens = precedence >= parentPrecedence;
2141 switch (op.
kind()) {
2142 case Operator::Kind::EQEQ:
2149 case Operator::Kind::NEQ:
2209 if (Precedence::kTernary >= parentPrecedence) {
2217 if (Precedence::kTernary >= parentPrecedence) {
2226 const Operator op = p.getOperator();
2227 if (op.
kind() == Operator::Kind::PLUS) {
2232 if (op.
kind() == Operator::Kind::MINUS && p.operand()->type().isMatrix()) {
2241 if (Precedence::kPrefix >= parentPrecedence) {
2248 if (Precedence::kPrefix >= parentPrecedence) {
2255 if (Precedence::kPostfix >= parentPrecedence) {
2260 if (Precedence::kPostfix >= parentPrecedence) {
2267 if (
type.isFloat()) {
2291 const char*& separator) {
2294 this->
write(separator);
2299 this->
write(separator);
2300 this->
write(
"_out");
2304 this->
write(separator);
2305 this->
write(
"_uniforms");
2309 this->
write(separator);
2310 this->
write(
"_globals");
2314 this->
write(separator);
2315 this->
write(
"_fragCoord");
2319 this->
write(separator);
2320 this->
write(
"sk_SampleMaskIn");
2324 this->
write(separator);
2325 this->
write(
"sk_VertexID");
2329 this->
write(separator);
2330 this->
write(
"sk_InstanceID");
2334 this->
write(separator);
2335 this->
write(
"_threadgroups");
2341 const char*& separator) {
2344 this->
write(separator);
2345 this->
write(
"Inputs _in");
2349 this->
write(separator);
2350 this->
write(
"thread Outputs& _out");
2354 this->
write(separator);
2355 this->
write(
"Uniforms _uniforms");
2359 this->
write(separator);
2360 this->
write(
"thread Globals& _globals");
2364 this->
write(separator);
2365 this->
write(
"float4 _fragCoord");
2369 this->
write(separator);
2370 this->
write(
"uint sk_SampleMaskIn");
2374 this->
write(separator);
2375 this->
write(
"uint sk_VertexID");
2379 this->
write(separator);
2380 this->
write(
"uint sk_InstanceID");
2384 this->
write(separator);
2385 this->
write(
"threadgroup Threadgroups& _threadgroups");
2396 return (layout.
fSet >= 0) ? layout.
fSet
2404 const char* separator =
"";
2407 this->
write(
"fragment Outputs fragmentMain(");
2409 this->
write(
"vertex Outputs vertexMain(");
2411 this->
write(
"kernel void computeMain(");
2417 this->
write(
"Inputs _in [[stage_in]]");
2421 this->
write(separator);
2422 this->
write(
"constant Uniforms& _uniforms [[buffer(" +
2441 this->
write(separator);
2449 this->
write(
" [[texture(");
2450 this->
write(std::to_string(binding));
2451 this->
write(
")]], sampler ");
2454 this->
write(
" [[sampler(");
2455 this->
write(std::to_string(binding));
2462 this->
write(
" [[texture(");
2463 this->
write(std::to_string(binding));
2467 std::string_view attr;
2470 attr =
" [[threadgroups_per_grid]]";
2473 attr =
" [[threadgroup_position_in_grid]]";
2476 attr =
" [[thread_position_in_threadgroup]]";
2479 attr =
" [[thread_position_in_grid]]";
2482 attr =
" [[thread_index_in_threadgroup]]";
2487 if (!attr.empty()) {
2488 this->
write(separator);
2498 if (intf.
typeName() ==
"sk_PerVertex") {
2501 this->
write(separator);
2503 this->
write(
"const ");
2509 this->
write(
" [[buffer(");
2518 this->
write(separator);
2519 this->
write(
"constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(1)]]");
2523 this->
write(separator);
2524 this->
write(
"bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]");
2526 this->
write(
", uint sk_SampleMaskIn [[sample_mask]]");
2534 this->
write(separator);
2535 this->
write(
"uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
2545 for (
const Variable* param : f.parameters()) {
2550 if (f.isMain() && param == f.getMainCoordsParameter()) {
2553 this->
write(separator);
2578 for (
int index = block.
size(); index--; ) {
2579 stmt = block[index].get();
2586 if (!stmt->
is<
Nop>()) {
2597 this->
write(
"Inputs _in = { ");
2598 const char* separator =
"";
2604 this->
write(separator);
2644 for (
const std::unique_ptr<Statement>& stmt : f.body()->as<
Block>().children()) {
2645 if (!stmt->isEmpty()) {
2667 this->
write(
"device ");
2669 this->
write(
"thread ");
2672 this->
write(
"const ");
2677 if (intf.
typeName() ==
"sk_PerVertex") {
2682 this->
write(
"struct ");
2710 int currentOffset = 0;
2711 for (
const Field& field : fields) {
2712 int fieldOffset = field.fLayout.fOffset;
2713 const Type* fieldType = field.fType;
2716 "' is not permitted here");
2719 if (fieldOffset != -1) {
2720 if (currentOffset > fieldOffset) {
2722 "offset of field '" + std::string(field.fName) +
2723 "' must be at least " + std::to_string(currentOffset));
2725 }
else if (currentOffset < fieldOffset) {
2726 this->
write(
"char pad");
2729 this->
write(std::to_string(fieldOffset - currentOffset));
2731 currentOffset = fieldOffset;
2736 "offset of field '" + std::string(field.fName) +
2737 "' must be a multiple of " + std::to_string(
alignment));
2755 size_t fieldSize = memoryLayout.
size(*fieldType);
2756 if (fieldSize >
static_cast<size_t>(std::numeric_limits<int>::max() - currentOffset)) {
2760 currentOffset += fieldSize;
2786 if (varDecl.
value()) {
2795 case Statement::Kind::kBlock:
2798 case Statement::Kind::kExpression:
2801 case Statement::Kind::kReturn:
2804 case Statement::Kind::kVarDeclaration:
2807 case Statement::Kind::kIf:
2810 case Statement::Kind::kFor:
2813 case Statement::Kind::kDo:
2816 case Statement::Kind::kSwitch:
2819 case Statement::Kind::kBreak:
2820 this->
write(
"break;");
2822 case Statement::Kind::kContinue:
2823 this->
write(
"continue;");
2825 case Statement::Kind::kDiscard:
2826 this->
write(
"discard_fragment();");
2828 case Statement::Kind::kNop:
2840 bool isScope =
b.isScope() ||
b.isEmpty();
2845 for (
const std::unique_ptr<Statement>& stmt :
b.children()) {
2846 if (!stmt->isEmpty()) {
2858 this->
write(
"if (");
2863 this->
write(
" else ");
2870 if (!f.initializer() && f.test() && !f.next()) {
2871 this->
write(
"while (");
2878 this->
write(
"for (");
2879 if (f.
initializer() && !f.initializer()->isEmpty()) {
2898 this->
write(
" while (");
2913 this->
write(
"switch (");
2917 for (
const std::unique_ptr<Statement>& stmt :
s.cases()) {
2922 this->
write(
"case ");
2941 this->
write(
"return _out;");
2943 this->
write(
"return;");
2953 this->
write(
"_out.sk_FragColor = ");
2958 "Metal does not support returning '" +
2959 r.
expression()->type().description() +
"' from main()");
2966 this->
write(
"return");
2975 this->
writeLine(
"#include <metal_stdlib>");
2976 this->
writeLine(
"#include <simd/simd.h>");
2978 this->
writeLine(
"#pragma clang diagnostic ignored \"-Wall\"");
2980 this->
writeLine(
"using namespace metal;");
2986 void visitSampler(
const Type&, std::string_view)
override {
2987 if (fWrotePolyfill) {
2990 fWrotePolyfill =
true;
2994 texture2d<half> tex;
2997half4 sample(sampler2D i, float2 p, float b=%g) { return i.tex.sample(i.smp, p, bias(b)); }
2998half4 sample(sampler2D i, float3 p, float b=%g) { return i.tex.sample(i.smp, p.xy / p.z, bias(b)); }
2999half4 sampleLod(sampler2D i, float2 p, float lod) { return i.tex.sample(i.smp, p, level(lod)); }
3000half4 sampleLod(sampler2D i, float3 p, float lod) {
3001 return i.tex.sample(i.smp, p.xy / p.z, level(lod));
3003half4 sampleGrad(sampler2D i, float2 p, float2 dPdx, float2 dPdy) {
3004 return i.tex.sample(i.smp, p, gradient2d(dPdx, dPdy));
3010 fCodeGen->write(polyfill.c_str());
3014 float fTextureBias = 0.0f;
3015 bool fWrotePolyfill =
false;
3018 visitor.fCodeGen =
this;
3029 if (var.modifierFlags().isUniform()) {
3035 this->
write(
"struct Uniforms {\n");
3039 "Metal backend requires all uniforms to have the same "
3040 "'layout(set=...)'");
3051 this->
write(
"};\n");
3056 this->
write(
"struct Inputs {\n");
3066 this->
write(
"device ");
3074 if (-1 != var.layout().fLocation) {
3076 this->
write(
" [[attribute(" + std::to_string(var.layout().fLocation) +
3079 this->
write(
" [[user(locn" + std::to_string(var.layout().fLocation) +
3087 this->
write(
"};\n");
3091 this->
write(
"struct Outputs {\n");
3093 this->
write(
" float4 sk_Position [[position]];\n");
3095 this->
write(
" half4 sk_FragColor [[color(0)]];\n");
3097 this->
write(
" half4 sk_SecondaryFragColor [[color(0), index(1)]];\n");
3105 this->
write(
" uint sk_SampleMask [[sample_mask]];\n");
3113 this->
write(
"device ");
3123 int location = var.layout().fLocation;
3127 "Metal out variables must have 'layout(location=...)'");
3129 this->
write(
" [[user(locn" + std::to_string(location) +
")]]");
3131 this->
write(
" [[color(" + std::to_string(location) +
")");
3132 int colorIndex = var.layout().fIndex;
3134 this->
write(
", index(" + std::to_string(colorIndex) +
")");
3143 this->
write(
" float sk_PointSize [[point_size]];\n");
3145 this->
write(
"};\n");
3149 bool wroteInterfaceBlock =
false;
3153 wroteInterfaceBlock =
true;
3156 if (!wroteInterfaceBlock &&
3158 this->
writeLine(
"struct sksl_synthetic_uniforms {");
3175 void visitConstantVariable(
const VarDeclaration& decl)
override {
3176 fCodeGen->write(
"constant ");
3177 fCodeGen->writeVarDeclaration(decl);
3178 fCodeGen->finishLine();
3184 visitor.fCodeGen =
this;
3192 if (ib->typeName() !=
"sk_PerVertex") {
3228 std::string_view blockName)
override {
3230 fCodeGen->write(
" ");
3232 fCodeGen->write(
"const ");
3234 fCodeGen->write(
is_buffer(block) ?
"device " :
"constant ");
3236 fCodeGen->write(
"* ");
3237 fCodeGen->writeName(blockName);
3238 fCodeGen->write(
";\n");
3240 void visitTexture(
const Type&
type, std::string_view
name)
override {
3242 fCodeGen->write(
" ");
3243 fCodeGen->writeType(
type);
3244 fCodeGen->write(
" ");
3245 fCodeGen->writeName(
name);
3246 fCodeGen->write(
";\n");
3248 void visitSampler(
const Type&, std::string_view
name)
override {
3250 fCodeGen->write(
" sampler2D ");
3251 fCodeGen->writeName(
name);
3252 fCodeGen->write(
";\n");
3254 void visitConstantVariable(
const VarDeclaration& decl)
override {
3259 fCodeGen->write(
" ");
3261 fCodeGen->writeType(var.
type());
3262 fCodeGen->write(
" ");
3264 fCodeGen->write(
";\n");
3268 fCodeGen->write(
"struct Globals {\n");
3274 fCodeGen->writeLine(
"};");
3283 visitor.fCodeGen =
this;
3292 std::string_view blockName)
override {
3294 fCodeGen->write(
"&");
3295 fCodeGen->writeName(blockName);
3297 void visitTexture(
const Type&, std::string_view
name)
override {
3299 fCodeGen->writeName(
name);
3301 void visitSampler(
const Type&, std::string_view
name)
override {
3303 fCodeGen->write(
"{");
3304 fCodeGen->writeName(
name);
3306 fCodeGen->write(
", ");
3307 fCodeGen->writeName(
name);
3309 fCodeGen->write(
"}");
3311 void visitConstantVariable(
const VarDeclaration& decl)
override {
3317 fCodeGen->writeVarInitializer(var, *
value);
3319 fCodeGen->write(
"{}");
3324 fCodeGen->write(
"Globals _globals{");
3327 fCodeGen->write(
", ");
3332 fCodeGen->writeLine(
"};");
3333 fCodeGen->writeLine(
"(void)_globals;");
3340 visitor.fCodeGen =
this;
3364 void visitNonconstantVariable(
const Variable& var)
override {
3366 fCodeGen->write(
" ");
3368 fCodeGen->writeType(var.
type());
3369 fCodeGen->write(
" ");
3371 fCodeGen->write(
";\n");
3375 fCodeGen->write(
"struct Threadgroups {\n");
3381 fCodeGen->writeLine(
"};");
3390 visitor.fCodeGen =
this;
3398 void visitNonconstantVariable(
const Variable& var)
override {
3400 fCodeGen->write(
"{}");
3404 fCodeGen->write(
"threadgroup Threadgroups _threadgroups{");
3407 fCodeGen->write(
", ");
3412 fCodeGen->writeLine(
"};");
3413 fCodeGen->writeLine(
"(void)_threadgroups;");
3420 visitor.fCodeGen =
this;
3427 case ProgramElement::Kind::kExtension:
3429 case ProgramElement::Kind::kGlobalVar:
3431 case ProgramElement::Kind::kInterfaceBlock:
3434 case ProgramElement::Kind::kStructDefinition:
3437 case ProgramElement::Kind::kFunction:
3440 case ProgramElement::Kind::kFunctionPrototype:
3443 case ProgramElement::Kind::kModifiers:
3447 SkDEBUGFAILF(
"unsupported program element: %s\n", e.description().c_str());
3455 using ProgramVisitor::visitStatement;
3457 bool visitExpression(
const Expression& e)
override {
3459 case Expression::Kind::kFunctionCall: {
3461 fRequirements |= fCodeGen->requirements(f.function());
3464 case Expression::Kind::kFieldAccess: {
3466 if (f.ownerKind() == FieldAccess::OwnerKind::kAnonymousInterfaceBlock) {
3467 fRequirements |= kGlobals_Requirement;
3472 case Expression::Kind::kVariableReference: {
3476 fRequirements |= kGlobals_Requirement | kFragCoord_Requirement;
3478 fRequirements |= kSampleMaskIn_Requirement;
3480 fRequirements |= kOutputs_Requirement;
3482 fRequirements |= kVertexID_Requirement;
3484 fRequirements |= kInstanceID_Requirement;
3485 }
else if (var.
storage() == Variable::Storage::kGlobal) {
3487 fRequirements |= kInputs_Requirement;
3489 fRequirements |= kOutputs_Requirement;
3491 fRequirements |= kUniforms_Requirement;
3493 fRequirements |= kThreadgroups_Requirement;
3495 fRequirements |= kGlobals_Requirement;
3503 return INHERITED::visitExpression(e);
3511 RequirementsVisitor visitor;
3513 visitor.fCodeGen =
this;
3514 visitor.visitStatement(*
s);
3516 return visitor.fRequirements;
3587 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)
Type::kYUV Type::kRGBA() int(0.7 *637)
virtual SkSpan< std::unique_ptr< Expression > > argumentSpan()=0
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
const BuiltinTypes & fTypes
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & statement()
void error(Position position, std::string_view msg)
const std::unique_ptr< Expression > & expression() const
virtual 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
Operator getOperator() const
std::unique_ptr< Expression > & operand()
Operator getOperator() const
std::unique_ptr< Expression > & operand()
std::unique_ptr< Expression > & expression()
std::unique_ptr< Expression > toLiteral(const ShaderCaps &caps) const
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
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 size_t slotCount() 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
static const uint8_t buffer[]
Dart_NativeFunction function
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)
static const char header[]
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)