Add SkMatrix::getPerspectiveTypeMaskOnly() and SkMatrix::isTriviallyIdentity().
Reduces profile time in setConcat() and computeTypeMask() for demos that
do a lot of matrix concatenation.



git-svn-id: http://skia.googlecode.com/svn/trunk@2191 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrDefaultPathRenderer.cpp b/gpu/src/GrDefaultPathRenderer.cpp
index b8b7f62..79d6e25 100644
--- a/gpu/src/GrDefaultPathRenderer.cpp
+++ b/gpu/src/GrDefaultPathRenderer.cpp
@@ -10,6 +10,7 @@
 
 #include "GrContext.h"
 #include "GrPathUtils.h"
+#include "SkString.h"
 #include "SkTrace.h"
 
 
@@ -372,9 +373,6 @@
 void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
                                        bool stencilOnly) {
 
-    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
-                    "points", SkStringPrintf("%i", path.countPoints()).c_str());
-
     GrMatrix viewM = fTarget->getViewMatrix();
     // In order to tesselate the path we get a bound on how much the matrix can
     // stretch when mapping to screen coordinates.
@@ -502,8 +500,6 @@
     }
 
     {
-    SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
-                    "verts", SkStringPrintf("%i", vert - base).c_str());
     for (int p = 0; p < passCount; ++p) {
         fTarget->setDrawFace(drawFace[p]);
         if (NULL != passes[p]) {
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 086aa98..7c2109c 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -67,10 +67,11 @@
     bool preservesAxisAlignment() const { return this->rectStaysRect(); }
 
     /**
-     *  Returns true if the perspective contains perspective elements.
+     *  Returns true if the matrix contains perspective elements.
      */
     bool hasPerspective() const {
-        return SkToBool(this->getType() & kPerspective_Mask);
+        return SkToBool(this->getPerspectiveTypeMaskOnly() &
+                        kPerspective_Mask);
     }
 
     enum {
@@ -536,6 +537,11 @@
         */
         kRectStaysRect_Mask = 0x10,
 
+        /** Set if the perspective bit is valid even though the rest of
+            the matrix is Unknown.
+        */
+        kOnlyPerspectiveValid_Mask = 0x40,
+
         kUnknown_Mask = 0x80,
 
         kORableMasks =  kTranslate_Mask |
@@ -554,10 +560,13 @@
     mutable uint8_t fTypeMask;
 
     uint8_t computeTypeMask() const;
+    uint8_t computePerspectiveTypeMask() const;
 
     void setTypeMask(int mask) {
         // allow kUnknown or a valid mask
-        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
+        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
+                 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask | kPerspective_Mask) & mask)
+                 == mask);
         fTypeMask = SkToU8(mask);
     }
 
@@ -571,6 +580,24 @@
         SkASSERT((mask & kAllMasks) == mask);
         fTypeMask &= ~mask;
     }
+
+    TypeMask getPerspectiveTypeMaskOnly() const {
+        if ((fTypeMask & kUnknown_Mask) &&
+            !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
+            fTypeMask = this->computePerspectiveTypeMask();
+        }
+        return (TypeMask)(fTypeMask & 0xF);
+    }
+
+    /** Returns true if we already know that the matrix is identity;
+        false otherwise.
+    */
+    bool isTriviallyIdentity() const {
+        if (fTypeMask & kUnknown_Mask) {
+            return false;
+        }
+        return ((fTypeMask & 0xF) == 0);
+    }
     
     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index ba8f596..3000533 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -56,6 +56,18 @@
     static const int32_t kPersp1Int  = (1 << 30);
 #endif
 
+uint8_t SkMatrix::computePerspectiveTypeMask() const {
+    unsigned mask = kOnlyPerspectiveValid_Mask | kUnknown_Mask;
+
+    if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
+            SkScalarAs2sCompliment(fMat[kMPersp1]) |
+            (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
+        mask |= kPerspective_Mask;
+    }
+
+    return SkToU8(mask);
+}
+
 uint8_t SkMatrix::computeTypeMask() const {
     unsigned mask = 0;
 
@@ -165,7 +177,7 @@
         fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
                           SkScalarMul(fMat[kMScaleY], dy);
 
-        this->setTypeMask(kUnknown_Mask);
+        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     }
     return true;
 }
@@ -180,7 +192,7 @@
     if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
         fMat[kMTransX] += dx;
         fMat[kMTransY] += dy;
-        this->setTypeMask(kUnknown_Mask);
+        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     }
     return true;
 }
@@ -324,7 +336,7 @@
     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     fMat[kMPersp2] = kMatrix22Elem;
     
-    this->setTypeMask(kUnknown_Mask);
+    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
 }
 
 void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
@@ -339,7 +351,7 @@
     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     fMat[kMPersp2] = kMatrix22Elem;
 
-    this->setTypeMask(kUnknown_Mask);
+    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
 }
 
 void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
@@ -392,7 +404,7 @@
     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     fMat[kMPersp2] = kMatrix22Elem;
 
-    this->setTypeMask(kUnknown_Mask);
+    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
 }
 
 void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
@@ -407,7 +419,7 @@
     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     fMat[kMPersp2] = kMatrix22Elem;
 
-    this->setTypeMask(kUnknown_Mask);
+    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
 }
 
 bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
@@ -573,12 +585,12 @@
 }
 
 bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
-    TypeMask aType = a.getType();
-    TypeMask bType = b.getType();
+    TypeMask aType = a.getPerspectiveTypeMaskOnly();
+    TypeMask bType = b.getPerspectiveTypeMaskOnly();
 
-    if (0 == aType) {
+    if (a.isTriviallyIdentity()) {
         *this = b;
-    } else if (0 == bType) {
+    } else if (b.isTriviallyIdentity()) {
         *this = a;
     } else {
         SkMatrix tmp;
@@ -615,6 +627,7 @@
             }
 
             normalize_perspective(tmp.fMat);
+            tmp.setTypeMask(kUnknown_Mask);
         } else {    // not perspective
             if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
                     a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
@@ -652,10 +665,12 @@
 
             tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
             tmp.fMat[kMPersp2] = kMatrix22Elem;
+            //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
+            //SkASSERT(!(tmp.getType() & kPerspective_Mask));
+            tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
         }
         *this = tmp;
     }
-    this->setTypeMask(kUnknown_Mask);
     return true;
 }
 
@@ -829,6 +844,7 @@
             }
             inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
 #endif
+            inv->setTypeMask(kUnknown_Mask);
         } else {   // not perspective
 #ifdef SK_SCALAR_IS_FIXED
             Sk64    tx, ty;
@@ -877,6 +893,7 @@
             inv->fMat[kMPersp0] = 0;
             inv->fMat[kMPersp1] = 0;
             inv->fMat[kMPersp2] = kMatrix22Elem;
+            inv->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
         }
 
         if (inv == &tmp) {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index a8d1942..cf94982 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1480,7 +1480,7 @@
                           const SkPaint& paint) {
     CHECK_SHOULD_DRAW(draw);
 
-    if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+    if (draw.fMatrix->hasPerspective()) {
         // this guy will just call our drawPath()
         draw.drawText((const char*)text, byteLength, x, y, paint);
     } else {
@@ -1508,7 +1508,7 @@
                              const SkPaint& paint) {
     CHECK_SHOULD_DRAW(draw);
 
-    if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+    if (draw.fMatrix->hasPerspective()) {
         // this guy will just call our drawPath()
         draw.drawPosText((const char*)text, byteLength, pos, constY,
                          scalarsPerPos, paint);