diff options
author | junov@chromium.org <junov@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-07-12 14:01:32 +0000 |
---|---|---|
committer | junov@chromium.org <junov@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-07-12 14:01:32 +0000 |
commit | 6fc5699e777c27c4eea9587a131aecf6e92a677a (patch) | |
tree | 489502fd6461984e3f7fb87c2061fd28032cece5 /src | |
parent | 50a69a0727076d6590a23dd0f6501371573c7d28 (diff) |
Fixing type mask computation in SkMatrix to make it faster and make it so that matrices have the same type masks as their inverses.
This patch also add bench tests that call invert() followed by mapRect() on various types of matrices. Performance of these tests was greatly affected by typemask computation
Review URL: http://codereview.appspot.com/6380043/
BUG=https://code.google.com/p/chromium/issues/detail?id=135259
git-svn-id: http://skia.googlecode.com/svn/trunk@4562 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkMatrix.cpp | 80 |
1 files changed, 53 insertions, 27 deletions
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index 85cb7c6bb9..c23a903a71 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -59,13 +59,27 @@ enum { uint8_t SkMatrix::computePerspectiveTypeMask() const { unsigned mask = kOnlyPerspectiveValid_Mask | kUnknown_Mask; +#ifdef SK_SCALAR_SLOW_COMPARES if (SkScalarAs2sCompliment(fMat[kMPersp0]) | SkScalarAs2sCompliment(fMat[kMPersp1]) | (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) { - mask |= kPerspective_Mask; + return SkToU8(kORableMasks); + } +#else + // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment + // is a win, but replacing those below is not. We don't yet understand + // that result. + if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || + fMat[kMPersp2] != kMatrix22Elem) { + // If this is a perspective transform, we return true for all other
+ // transform flags - this does not disable any optimizations, respects
+ // the rule that the type mask must be conservative, and speeds up + // type mask computation. + return SkToU8(kORableMasks); } +#endif - return SkToU8(mask); + return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask); } uint8_t SkMatrix::computeTypeMask() const { @@ -75,7 +89,7 @@ uint8_t SkMatrix::computeTypeMask() const { if (SkScalarAs2sCompliment(fMat[kMPersp0]) | SkScalarAs2sCompliment(fMat[kMPersp1]) | (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) { - mask |= kPerspective_Mask; + return SkToU8(kORableMasks); } if (SkScalarAs2sCompliment(fMat[kMTransX]) | @@ -83,12 +97,11 @@ uint8_t SkMatrix::computeTypeMask() const { mask |= kTranslate_Mask; } #else - // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment - // is a win, but replacing those below is not. We don't yet understand - // that result. if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != kMatrix22Elem) { - mask |= kPerspective_Mask; + // Once it is determined that that this is a perspective transform, + // all other flags are moot as far as optimizations are concerned. + return SkToU8(kORableMasks); } if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) { @@ -102,30 +115,43 @@ uint8_t SkMatrix::computeTypeMask() const { int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]); if (m01 | m10) { - mask |= kAffine_Mask; - } + // The skew components may be scale-inducing, unless we are dealing + // with a pure rotation. Testing for a pure rotation is expensive, + // so we opt for being conservative by always setting the scale bit. + // along with affine. + // By doing this, we are also ensuring that matrices have the same + // type masks as their inverses. + mask |= kAffine_Mask | kScale_Mask; + + // For rectStaysRect, in the affine case, we only need check that + // the primary diagonal is all zeros and that the secondary diagonal + // is all non-zero. - if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { - mask |= kScale_Mask; - } - - if ((mask & kPerspective_Mask) == 0) { // map non-zero to 1 - m00 = m00 != 0; m01 = m01 != 0; m10 = m10 != 0; - m11 = m11 != 0; - // record if the (p)rimary and (s)econdary diagonals are all 0 or - // all non-zero (answer is 0 or 1) - int dp0 = (m00 | m11) ^ 1; // true if both are 0 - int dp1 = m00 & m11; // true if both are 1 - int ds0 = (m01 | m10) ^ 1; // true if both are 0 + int dp0 = 0 == (m00 | m11) ; // true if both are 0 int ds1 = m01 & m10; // true if both are 1 - // return 1 if primary is 1 and secondary is 0 or - // primary is 0 and secondary is 1 - mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; + mask |= (dp0 & ds1) << kRectStaysRect_Shift; + } else { + // Only test for scale explicitly if not affine, since affine sets the + // scale bit. + if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { + mask |= kScale_Mask; + } + + // Not affine, therefore we already know secondary diagonal is + // all zeros, so we just need to check that primary diagonal is + // all non-zero. + + // map non-zero to 1 + m00 = m00 != 0; + m11 = m11 != 0; + + // record if the (p)rimary diagonal is all non-zero + mask |= (m00 & m11) << kRectStaysRect_Shift; } return SkToU8(mask); @@ -831,7 +857,6 @@ bool SkMatrix::invert(SkMatrix* inv) const { if (inv == this) { inv = &tmp; } - inv->setTypeMask(kUnknown_Mask); if (isPersp) { shift = 61 - shift; @@ -862,7 +887,6 @@ bool SkMatrix::invert(SkMatrix* inv) const { } inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]); #endif - inv->setTypeMask(kUnknown_Mask); } else { // not perspective #ifdef SK_SCALAR_IS_FIXED Sk64 tx, ty; @@ -911,9 +935,11 @@ bool SkMatrix::invert(SkMatrix* inv) const { inv->fMat[kMPersp0] = 0; inv->fMat[kMPersp1] = 0; inv->fMat[kMPersp2] = kMatrix22Elem; - inv->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask); + } + inv->setTypeMask(fTypeMask); + if (inv == &tmp) { *(SkMatrix*)this = tmp; } |