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
This commit is contained in:
reed 2016-06-30 06:38:54 -07:00 committed by Commit bot
parent 501ca7f538
commit 47df89ebfd
4 changed files with 89 additions and 3 deletions

View File

@ -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); )

View File

@ -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.

View File

@ -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];

View File

@ -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]);
}
}