Add support for matrix division to Metal codegen.
This CL adds a polyfill for componentwise matrix/matrix division to
Metal, as well as matrix/=matrix. Matrix/scalar and scalar/matrix
division work by splatting the scalar out to a matrix (handled in the
prior CL, http://review.skia.org/407616) and then performing
componentwise matrix/matrix division.
Working demonstration (copy-pasted from the Metal output file):
http://screen/BrqyPcbPrB7Dy4m
Change-Id: I6a8b97783be3485f7ffee551b669d14bc58e7568
Bug: skia:11125
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/407796
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
index 79bea71..c265756 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
@@ -1215,7 +1215,15 @@
void MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Type& right,
const Type& result) {
- String key = "TimesEqual " + this->typeName(left) + ":" + this->typeName(right);
+ SkASSERT(left.isMatrix());
+ SkASSERT(right.isMatrix());
+ SkASSERT(result.isMatrix());
+ SkASSERT(left.rows() == right.rows());
+ SkASSERT(left.columns() == right.columns());
+ SkASSERT(left.rows() == result.rows());
+ SkASSERT(left.columns() == result.columns());
+
+ String key = "Matrix *= " + this->typeName(left) + ":" + this->typeName(right);
auto [iter, wasInserted] = fHelpers.insert(key);
if (wasInserted) {
@@ -1234,7 +1242,7 @@
SkASSERT(left.rows() == right.rows());
SkASSERT(left.columns() == right.columns());
- String key = "MatrixEquality " + this->typeName(left) + ":" + this->typeName(right);
+ String key = "Matrix == " + this->typeName(left) + ":" + this->typeName(right);
auto [iter, wasInserted] = fHelpers.insert(key);
if (wasInserted) {
@@ -1259,6 +1267,36 @@
}
}
+void MetalCodeGenerator::writeMatrixDivisionHelpers(const Type& type) {
+ SkASSERT(type.isMatrix());
+
+ String key = "Matrix / " + this->typeName(type);
+
+ auto [iter, wasInserted] = fHelpers.insert(key);
+ if (wasInserted) {
+ String typeName = this->typeName(type);
+
+ fExtraFunctions.printf(
+ "thread %s operator/(const %s left, const %s right) {\n"
+ " return %s(",
+ typeName.c_str(), typeName.c_str(), typeName.c_str(), typeName.c_str());
+
+ const char* separator = "";
+ for (int index=0; index<type.columns(); ++index) {
+ fExtraFunctions.printf("%sleft[%d] / right[%d]", separator, index, index);
+ separator = ", ";
+ }
+
+ fExtraFunctions.printf(");\n"
+ "}\n"
+ "thread %s& operator/=(thread %s& left, thread const %s& right) {\n"
+ " left = left / right;\n"
+ " return left;\n"
+ "}\n",
+ typeName.c_str(), typeName.c_str(), typeName.c_str());
+ }
+}
+
void MetalCodeGenerator::writeArrayEqualityHelpers(const Type& type) {
SkASSERT(type.isArray());
@@ -1387,13 +1425,18 @@
default:
break;
}
- if (needParens) {
- this->write("(");
- }
if (leftType.isMatrix() && rightType.isMatrix() && op.kind() == Token::Kind::TK_STAREQ) {
this->writeMatrixTimesEqualHelper(leftType, rightType, b.type());
}
-
+ if (op.removeAssignment().kind() == Token::Kind::TK_SLASH &&
+ ((leftType.isMatrix() && rightType.isMatrix()) ||
+ (leftType.isScalar() && rightType.isMatrix()) ||
+ (leftType.isMatrix() && rightType.isScalar()))) {
+ this->writeMatrixDivisionHelpers(leftType.isMatrix() ? leftType : rightType);
+ }
+ if (needParens) {
+ this->write("(");
+ }
bool needMatrixSplatOnScalar = rightType.isMatrix() && leftType.isScalar() &&
op.removeAssignment().kind() != Token::Kind::TK_STAR;
if (needMatrixSplatOnScalar) {