aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2016-06-30 06:38:54 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-30 06:38:54 -0700
commit47df89ebfd548de2ccd91387e1d7eee418b65f96 (patch)
tree97ef6df66cec123f559f7feb98dd5942670bf744
parent501ca7f538f129efd27113e641ad17363920886e (diff)
speed up maprect for scale+trans case
-rw-r--r--bench/MatrixBench.cpp34
-rw-r--r--include/core/SkMatrix.h6
-rw-r--r--src/core/SkMatrix.cpp26
-rw-r--r--tests/MatrixTest.cpp26
4 files changed, 89 insertions, 3 deletions
diff --git a/bench/MatrixBench.cpp b/bench/MatrixBench.cpp
index a185fec589..53e7296731 100644
--- a/bench/MatrixBench.cpp
+++ b/bench/MatrixBench.cpp
@@ -297,3 +297,37 @@ DEF_BENCH( return new MapPointsMatrixBench("mappoints_identity", SkMatrix::I());
DEF_BENCH( return new MapPointsMatrixBench("mappoints_trans", make_trans()); )
DEF_BENCH( return new MapPointsMatrixBench("mappoints_scale", make_scale()); )
DEF_BENCH( return new MapPointsMatrixBench("mappoints_affine", make_afine()); )
+
+///////////////////////////////////////////////////////////////////////////////
+
+class MapRectMatrixBench : public MatrixBench {
+ SkMatrix fM;
+ SkRect fR;
+ bool fScaleTrans;
+
+ enum { MEGA_LOOP = 1000 * 1000 };
+public:
+ MapRectMatrixBench(const char name[], bool scale_trans)
+ : MatrixBench(name), fScaleTrans(scale_trans)
+ {
+ fM.setScale(2, 3);
+ fM.postTranslate(1, 2);
+
+ fR.set(10, 10, 100, 200);
+ }
+
+ void performTest() override {
+ SkRect dst;
+ if (fScaleTrans) {
+ for (int i = 0; i < MEGA_LOOP; ++i) {
+ fM.mapRectScaleTranslate(&dst, fR);
+ }
+ } else {
+ for (int i = 0; i < MEGA_LOOP; ++i) {
+ fM.mapRect(&dst, fR);
+ }
+ }
+ }
+};
+DEF_BENCH( return new MapRectMatrixBench("maprect", false); )
+DEF_BENCH( return new MapRectMatrixBench("maprectscaletrans", true); )
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 6738a0eb69..d6d029597f 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -561,6 +561,12 @@ public:
this->mapPoints(dst, 4);
}
+ /**
+ * Maps a rect to another rect, asserting (in debug mode) that the matrix only contains
+ * scale and translate elements. If it contains other elements, the results are undefined.
+ */
+ void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
+
/** Return the mean radius of a circle after it has been mapped by
this matrix. NOTE: in perspective this value assumes the circle
has its center at the origin.
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index 5711bd9aef..492f3f6ac4 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1097,12 +1097,32 @@ void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
}
}
+void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
+ SkASSERT(dst);
+ SkASSERT(this->isScaleTranslate());
+
+ SkScalar sx = fMat[kMScaleX];
+ SkScalar sy = fMat[kMScaleY];
+ SkScalar tx = fMat[kMTransX];
+ SkScalar ty = fMat[kMTransY];
+ Sk4f scale(sx, sy, sx, sy);
+ Sk4f trans(tx, ty, tx, ty);
+
+ Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
+ // need to sort so we're not inverted
+ Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
+ Sk4f min = Sk4f::Min(ltrb, rblt);
+ Sk4f max = Sk4f::Max(ltrb, rblt);
+ // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
+ // ARM this sequence generates the fastest (a single instruction).
+ Sk4f(min[2], min[3], max[0], max[1]).store(&dst->fLeft);
+}
+
bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
SkASSERT(dst);
- if (this->rectStaysRect()) {
- this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
- dst->sort();
+ if (this->isScaleTranslate()) {
+ this->mapRectScaleTranslate(dst, src);
return true;
} else {
SkPoint quad[4];
diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp
index 2f91ccae97..01b2ba4e43 100644
--- a/tests/MatrixTest.cpp
+++ b/tests/MatrixTest.cpp
@@ -953,3 +953,29 @@ DEF_TEST(Matrix_Concat, r) {
REPORTER_ASSERT(r, expected == SkMatrix::Concat(a, b));
}
+
+// Test that all variants of maprect are correct.
+DEF_TEST(Matrix_maprects, r) {
+ const SkScalar scale = 1000;
+
+ SkMatrix mat;
+ mat.setScale(2, 3);
+ mat.postTranslate(1, 4);
+
+ SkRandom rand;
+ for (int i = 0; i < 10000; ++i) {
+ SkRect src = SkRect::MakeLTRB(rand.nextSScalar1() * scale,
+ rand.nextSScalar1() * scale,
+ rand.nextSScalar1() * scale,
+ rand.nextSScalar1() * scale);
+ SkRect dst[3];
+
+ mat.mapPoints((SkPoint*)&dst[0].fLeft, (SkPoint*)&src.fLeft, 2);
+ dst[0].sort();
+ mat.mapRect(&dst[1], src);
+ mat.mapRectScaleTranslate(&dst[2], src);
+
+ REPORTER_ASSERT(r, dst[0] == dst[1]);
+ REPORTER_ASSERT(r, dst[0] == dst[2]);
+ }
+}