added optimizations to speed up skinning

Docs-Preview: https://skia.org/?cl=145148
Bug: skia:
Change-Id: If27722105a1e8999f6440b6fd4044cc1f327827e
Reviewed-on: https://skia-review.googlesource.com/145148
Commit-Queue: Ruiqi Mao <ruiqimao@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 594ecb3..9a743b1 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -25,6 +25,7 @@
 #include "SkPaint.h"
 #include "SkRasterHandleAllocator.h"
 #include "SkSurfaceProps.h"
+#include "SkVertices.h"
 
 class GrContext;
 class GrRenderTargetContext;
@@ -50,7 +51,6 @@
 class SkSurface;
 class SkSurface_Base;
 class SkTextBlob;
-class SkVertices;
 
 /** \class SkCanvas
     SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed.
@@ -2149,7 +2149,7 @@
         The first element of bones should be an object to world space transformation matrix that
         will be applied before performing mesh deformations. If no such transformation is needed,
         it should be the identity matrix.
-        boneCount must be at most 100, and thus the size of bones should be at most 100.
+        boneCount must be at most 80, and thus the size of bones should be at most 80.
 
         @param vertices   triangle mesh to draw
         @param bones      bone matrix data
@@ -2157,7 +2157,7 @@
         @param mode       combines vertices colors with SkShader, if both are present
         @param paint      specifies the SkShader, used as SkVertices texture, may be nullptr
     */
-    void drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+    void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount,
                       SkBlendMode mode, const SkPaint& paint);
 
     /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to
@@ -2167,7 +2167,7 @@
         The first element of bones should be an object to world space transformation matrix that
         will be applied before performing mesh deformations. If no such transformation is needed,
         it should be the identity matrix.
-        boneCount must be at most 100, and thus the size of bones should be at most 100.
+        boneCount must be at most 80, and thus the size of bones should be at most 80.
 
         @param vertices   triangle mesh to draw
         @param bones      bone matrix data
@@ -2175,8 +2175,8 @@
         @param mode       combines vertices colors with SkShader, if both are present
         @param paint      specifies the SkShader, used as SkVertices texture, may be nullptr
     */
-    void drawVertices(const sk_sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
-                      SkBlendMode mode, const SkPaint& paint);
+    void drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
+                      int boneCount, SkBlendMode mode, const SkPaint& paint);
 
     /** Draws a Coons patch: the interpolation of four cubics with shared corners,
         associating a color, and optionally a texture SkPoint, with each corner.
@@ -2496,7 +2496,7 @@
                                       const SkPaint& paint) {
         this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
     }
-    virtual void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+    virtual void onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
                                       int boneCount, SkBlendMode mode, const SkPaint& paint);
 
     virtual void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint);
diff --git a/include/core/SkCanvasVirtualEnforcer.h b/include/core/SkCanvasVirtualEnforcer.h
index 84b209d..7e779a1 100644
--- a/include/core/SkCanvasVirtualEnforcer.h
+++ b/include/core/SkCanvasVirtualEnforcer.h
@@ -48,8 +48,8 @@
                      const SkPaint& paint) override = 0;
     void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
                       const SkPaint& paint) override = 0;
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) override = 0;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override = 0;
 
     void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
                      const SkPaint* paint) override = 0;
diff --git a/include/core/SkOverdrawCanvas.h b/include/core/SkOverdrawCanvas.h
index 380f9eb..aab47d4 100644
--- a/include/core/SkOverdrawCanvas.h
+++ b/include/core/SkOverdrawCanvas.h
@@ -39,8 +39,8 @@
     void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
     void onDrawRRect(const SkRRect&, const SkPaint&) override;
     void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override;
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override;
     void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                      int, SkBlendMode, const SkRect*, const SkPaint*) override;
     void onDrawPath(const SkPath&, const SkPaint&) override;
diff --git a/include/core/SkVertices.h b/include/core/SkVertices.h
index 9c1300b..63a27a0 100644
--- a/include/core/SkVertices.h
+++ b/include/core/SkVertices.h
@@ -24,6 +24,18 @@
     // to 0.
     struct BoneIndices {
         uint32_t indices[4];
+
+        uint32_t& operator[] (int i) {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 4);
+            return indices[i];
+        }
+
+        const uint32_t& operator[] (int i) const {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 4);
+            return indices[i];
+        }
     };
 
     // BoneWeights stores the interpolation weight for each of the (maximum of 4) bones a given
@@ -31,6 +43,55 @@
     // slot should be 0.
     struct BoneWeights {
         float weights[4];
+
+        float& operator[] (int i) {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 4);
+            return weights[i];
+        }
+
+        const float& operator[] (int i) const {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 4);
+            return weights[i];
+        }
+    };
+
+    // Bone stores a 3x2 transformation matrix in column major order:
+    // | scaleX   skewX transX |
+    // |  skewY  scaleY transY |
+    // SkRSXform is insufficient because bones can have non uniform scale.
+    struct Bone {
+        float values[6];
+
+        float& operator[] (int i) {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 6);
+            return values[i];
+        }
+
+        const float& operator[] (int i) const {
+            SkASSERT(i >= 0);
+            SkASSERT(i < 6);
+            return values[i];
+        }
+
+        SkPoint mapPoint(const SkPoint& point) const {
+            float x = values[0] * point.x() + values[2] * point.y() + values[4];
+            float y = values[1] * point.x() + values[3] * point.y() + values[5];
+            return SkPoint::Make(x, y);
+        }
+
+        SkRect mapRect(const SkRect& rect) const {
+            SkRect dst = SkRect::MakeEmpty();
+            SkPoint quad[4];
+            rect.toQuad(quad);
+            for (int i = 0; i < 4; i ++) {
+                quad[i] = mapPoint(quad[i]);
+            }
+            dst.setBoundsNoCheck(quad, 4);
+            return dst;
+        }
     };
 
     enum VertexMode {
@@ -168,6 +229,8 @@
 
     bool isVolatile() const { return fIsVolatile; }
 
+    sk_sp<SkVertices> applyBones(const Bone bones[], int boneCount) const;
+
     // returns approximate byte size of the vertices object
     size_t approximateSize() const;
 
diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h
index e29e0b5..0b43da6 100644
--- a/include/utils/SkLuaCanvas.h
+++ b/include/utils/SkLuaCanvas.h
@@ -58,8 +58,8 @@
                          const SkPaint*, SrcRectConstraint) override;
     void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
                           const SkPaint*) override;
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override;
 
     void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index f7307d9..793081a 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -71,8 +71,8 @@
                          const SkPaint*) override;
     void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
                           const SkPaint*) override;
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override;
     void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                      int, SkBlendMode, const SkRect*, const SkPaint*) override;
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h
index 0e86ed6..5043131 100644
--- a/include/utils/SkNoDrawCanvas.h
+++ b/include/utils/SkNoDrawCanvas.h
@@ -75,7 +75,7 @@
                             const SkPaint*) override {}
     void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
                              const SkPaint*) override {}
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode,
                               const SkPaint&) override {}
     void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                      int, SkBlendMode, const SkRect*, const SkPaint*) override {}
diff --git a/include/utils/SkPaintFilterCanvas.h b/include/utils/SkPaintFilterCanvas.h
index 4728792..1a5b59d 100644
--- a/include/utils/SkPaintFilterCanvas.h
+++ b/include/utils/SkPaintFilterCanvas.h
@@ -88,8 +88,8 @@
                          const SkPaint*) override;
     void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
                             const SkPaint*) override;
-    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override;
     void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
                              const SkPoint texCoords[4], SkBlendMode,
                              const SkPaint& paint) override;