diff options
author | reed <reed@google.com> | 2016-06-30 06:38:54 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-30 06:38:54 -0700 |
commit | 47df89ebfd548de2ccd91387e1d7eee418b65f96 (patch) | |
tree | 97ef6df66cec123f559f7feb98dd5942670bf744 | |
parent | 501ca7f538f129efd27113e641ad17363920886e (diff) |
speed up maprect for scale+trans case
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2111703002
Review-Url: https://codereview.chromium.org/2111703002
-rw-r--r-- | bench/MatrixBench.cpp | 34 | ||||
-rw-r--r-- | include/core/SkMatrix.h | 6 | ||||
-rw-r--r-- | src/core/SkMatrix.cpp | 26 | ||||
-rw-r--r-- | tests/MatrixTest.cpp | 26 |
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]); + } +} |