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/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 7b11980..52fed02 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -593,8 +593,8 @@
 #endif
 }
 
-void SkBitmapDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
-                                  SkBlendMode bmode, const SkPaint& paint) {
+void SkBitmapDevice::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
+                                  int boneCount, SkBlendMode bmode, const SkPaint& paint) {
     BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
                               vertices->texCoords(), vertices->colors(), vertices->boneIndices(),
                               vertices->boneWeights(), bmode, vertices->indices(),
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index a578d2c..65971ed 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -102,7 +102,7 @@
                         const SkPaint&, SkCanvas::SrcRectConstraint) override;
 
     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
-    void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint& paint) override;
     void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;
 
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 1da6e28..fb9e499 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1678,16 +1678,16 @@
     this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
 }
 
-void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
-                            SkBlendMode mode, const SkPaint& paint) {
+void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
+                            int boneCount, SkBlendMode mode, const SkPaint& paint) {
     TRACE_EVENT0("skia", TRACE_FUNC);
     RETURN_ON_NULL(vertices);
     SkASSERT(boneCount <= 80);
     this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
 }
 
-void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
-                            SkBlendMode mode, const SkPaint& paint) {
+void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
+                            int boneCount, SkBlendMode mode, const SkPaint& paint) {
     TRACE_EVENT0("skia", TRACE_FUNC);
     RETURN_ON_NULL(vertices);
     SkASSERT(boneCount <= 80);
@@ -2576,7 +2576,7 @@
     this->onDrawTextBlob(blob, x, y, paint);
 }
 
-void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
                                     int boneCount, SkBlendMode bmode, const SkPaint& paint) {
     LOOPER_BEGIN(paint, nullptr)
 
diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp
index 949dd4a..d0032b4 100644
--- a/src/core/SkColorSpaceXformCanvas.cpp
+++ b/src/core/SkColorSpaceXformCanvas.cpp
@@ -90,7 +90,8 @@
                       const SkPaint& paint) override {
         fTarget->drawPoints(mode, count, pts, fXformer->apply(paint));
     }
-    void onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
+
+    void onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount,
                               SkBlendMode mode, const SkPaint& paint) override {
         sk_sp<SkVertices> copy;
         if (vertices->hasColors()) {
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index e00ffdd..ad07e81 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -213,8 +213,8 @@
                                   const SkRect& dst, const SkPaint&);
 
 
-    virtual void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
-                              const SkPaint&) = 0;
+    virtual void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) = 0;
     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
 
     virtual void drawGlyphRunList(const SkGlyphRunList& glyphRunList);
@@ -420,7 +420,7 @@
     void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
                      const SkPaint&) override {}
     void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
-    void drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode,
                       const SkPaint&) override {}
 
 private:
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index ca37c09..bf023bc 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -74,7 +74,7 @@
                          const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
                          const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode,
                          const uint16_t indices[], int ptCount,
-                         const SkPaint& paint, const SkMatrix* bones, int boneCount) const;
+                         const SkPaint& paint, const SkVertices::Bone bones[], int boneCount) const;
 
     /**
      *  Overwrite the target with the path's coverage (i.e. its mask).
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index 4d1ccea..b9320d4 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -167,7 +167,8 @@
                           const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
                           const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode,
                           const uint16_t indices[], int indexCount,
-                          const SkPaint& paint, const SkMatrix* bones, int boneCount) const {
+                          const SkPaint& paint, const SkVertices::Bone bones[],
+                          int boneCount) const {
     SkASSERT(0 == vertexCount || vertices);
 
     // abort early if there is nothing to draw
@@ -207,11 +208,9 @@
     }
 
     constexpr size_t kDefVertexCount = 16;
-    constexpr size_t kDefBoneCount = 8;
     constexpr size_t kOuterSize = sizeof(SkTriColorShader) +
                                  sizeof(SkComposeShader) +
-                                 (2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount +
-                                 sizeof(SkMatrix) * kDefBoneCount;
+                                 (2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount;
     SkSTArenaAlloc<kOuterSize> outerAlloc;
 
     // deform vertices using the skeleton if it is passed in
@@ -219,28 +218,21 @@
         // allocate space for the deformed vertices
         SkPoint* deformed = outerAlloc.makeArray<SkPoint>(vertexCount);
 
-        // get the bone matrices
-        SkMatrix* transformedBones = outerAlloc.makeArray<SkMatrix>(boneCount);
-
-        // transform the bone matrices by the world transform
-        transformedBones[0] = bones[0];
-        for (int i = 1; i < boneCount; i ++) {
-            transformedBones[i] = SkMatrix::Concat(bones[i], bones[0]);
-        }
-
         // deform the vertices
         if (boneIndices && boneWeights) {
             for (int i = 0; i < vertexCount; i ++) {
                 const SkVertices::BoneIndices& indices = boneIndices[i];
                 const SkVertices::BoneWeights& weights = boneWeights[i];
 
+                // apply the world transform
+                SkPoint worldPoint = bones[0].mapPoint(vertices[i]);
+
                 // apply bone deformations
-                SkPoint result = SkPoint::Make(0.0f, 0.0f);
-                SkPoint transformed;
+                deformed[i] = SkPoint::Make(0.0f, 0.0f);
                 for (uint32_t j = 0; j < 4; j ++) {
                     // get the attachment data
-                    uint32_t index = indices.indices[j];
-                    float weight = weights.weights[j];
+                    uint32_t index = indices[j];
+                    float weight = weights[j];
 
                     // skip the bone if there is no weight
                     if (weight == 0.0f) {
@@ -248,19 +240,14 @@
                     }
                     SkASSERT(index != 0);
 
-                    // transformed = M * v
-                    transformedBones[index].mapPoints(&transformed, &vertices[i], 1);
-
-                    // result += transformed * w
-                    result += transformed * weight;
+                    // deformed += M * v * w
+                    deformed[i] += bones[index].mapPoint(worldPoint) * weight;
                 }
-
-                // set the deformed point
-                deformed[i] = result;
             }
         } else {
             // no bones, so only apply world transform
-            const SkMatrix& worldTransform = bones[0];
+            SkMatrix worldTransform = SkMatrix::I();
+            worldTransform.setAffine(bones[0].values);
             worldTransform.mapPoints(deformed, vertices, vertexCount);
         }
 
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index ea3ca6d..d4e3901 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -455,7 +455,7 @@
         SkBlendMode mode;
         SkPaint paint;
         void draw(SkCanvas* c, const SkMatrix&) const {
-            c->drawVertices(vertices, pod<SkMatrix>(this), boneCount, mode, paint);
+            c->drawVertices(vertices, pod<SkVertices::Bone>(this), boneCount, mode, paint);
         }
     };
     struct DrawAtlas final : Op {
@@ -660,9 +660,9 @@
     void* pod = this->push<DrawPoints>(count*sizeof(SkPoint), mode, count, paint);
     copy_v(pod, points,count);
 }
-void SkLiteDL::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
-                            SkBlendMode mode, const SkPaint& paint) {
-    void* pod = this->push<DrawVertices>(boneCount * sizeof(SkMatrix),
+void SkLiteDL::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
+                            int boneCount, SkBlendMode mode, const SkPaint& paint) {
+    void* pod = this->push<DrawVertices>(boneCount * sizeof(SkVertices::Bone),
                                          vertices,
                                          boneCount,
                                          mode,
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index aa32e02..ffcdb89 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -72,7 +72,7 @@
     void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4],
                    SkBlendMode, const SkPaint&);
     void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&);
-    void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint&);
     void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
                    SkBlendMode, const SkRect*, const SkPaint*);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index 971e62c..fedfa99 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -175,8 +175,9 @@
                                   const SkPaint& paint) {
     fDL->drawPoints(mode, count, pts, paint);
 }
-void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
-                                          int boneCount, SkBlendMode mode, const SkPaint& paint) {
+void SkLiteRecorder::onDrawVerticesObject(const SkVertices* vertices,
+                                          const SkVertices::Bone bones[], int boneCount,
+                                          SkBlendMode mode, const SkPaint& paint) {
     fDL->drawVertices(vertices, bones, boneCount, mode, paint);
 }
 void SkLiteRecorder::onDrawAtlas(const SkImage* atlas,
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index bc37546..5ae08fa 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -73,8 +73,8 @@
     void onDrawPatch(const SkPoint[12], const SkColor[4],
                      const SkPoint[4], SkBlendMode, const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], 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/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp
index 0e20878..4e6b8c5 100644
--- a/src/core/SkOverdrawCanvas.cpp
+++ b/src/core/SkOverdrawCanvas.cpp
@@ -216,9 +216,9 @@
     fList[0]->onDrawPoints(mode, count, points, this->overdrawPaint(paint));
 }
 
-void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
-                                            int boneCount, SkBlendMode blendMode,
-                                            const SkPaint& paint) {
+void SkOverdrawCanvas::onDrawVerticesObject(const SkVertices* vertices,
+                                            const SkVertices::Bone bones[], int boneCount,
+                                            SkBlendMode blendMode, const SkPaint& paint) {
     fList[0]->onDrawVerticesObject(vertices,
                                    bones,
                                    boneCount,
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index f63abe7..4ee0eae 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -616,9 +616,9 @@
             const SkPaint* paint = fPictureData->getPaint(reader);
             const SkVertices* vertices = fPictureData->getVertices(reader);
             const int boneCount = reader->readInt();
-            const SkMatrix* bones = boneCount ?
-                                    (const SkMatrix*) reader->skip(boneCount, sizeof(SkMatrix)) :
-                                    nullptr;
+            const SkVertices::Bone* bones = boneCount ?
+                    (const SkVertices::Bone*) reader->skip(boneCount, sizeof(SkVertices::Bone)) :
+                    nullptr;
             SkBlendMode bmode = reader->read32LE(SkBlendMode::kLastMode);
             BREAK_ON_READ_ERROR(reader);
 
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index ca36e7e..81e5135 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -682,16 +682,17 @@
     this->validate(initialOffset, size);
 }
 
-void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
-                                           int boneCount, SkBlendMode mode, const SkPaint& paint) {
+void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices,
+                                           const SkVertices::Bone bones[], int boneCount,
+                                           SkBlendMode mode, const SkPaint& paint) {
     // op + paint index + vertices index + number of bones + bone matrices + mode
-    size_t size = 5 * kUInt32Size + boneCount * sizeof(SkMatrix);
+    size_t size = 5 * kUInt32Size + boneCount * sizeof(SkVertices::Bone);
     size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
 
     this->addPaint(paint);
     this->addVertices(vertices);
     this->addInt(boneCount);
-    fWriter.write(bones, boneCount * sizeof(SkMatrix));
+    fWriter.write(bones, boneCount * sizeof(SkVertices::Bone));
     this->addInt(static_cast<uint32_t>(mode));
 
     this->validate(initialOffset, size);
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index dc9f4d9..dcec581 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -196,8 +196,8 @@
     void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst,
                             const SkPaint*) override;
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) 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/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 1abd582..f7c8dd4 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -317,7 +317,7 @@
     }
 }
 
-void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
                                       int boneCount, SkBlendMode bmode, const SkPaint& paint) {
     this->append<SkRecords::DrawVertices>(paint,
                                           sk_ref_sp(const_cast<SkVertices*>(vertices)),
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 7fed8ea..ce1131f 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -121,8 +121,8 @@
                             const SkPaint*) override;
     void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, 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 count, SkBlendMode, const SkRect* cull, const SkPaint*) override;
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 4ec2ae6..cce68c9 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -344,7 +344,7 @@
 RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
         SkPaint paint;
         sk_sp<SkVertices> vertices;
-        PODArray<SkMatrix> bones;
+        PODArray<SkVertices::Bone> bones;
         int boneCount;
         SkBlendMode bmode);
 RECORD(DrawShadowRec, kDraw_Tag,
diff --git a/src/core/SkVertices.cpp b/src/core/SkVertices.cpp
index 97a136c..a3a3989 100644
--- a/src/core/SkVertices.cpp
+++ b/src/core/SkVertices.cpp
@@ -207,6 +207,69 @@
     return const_cast<uint16_t*>(fVertices->indices());
 }
 
+/** Makes a copy of the SkVertices and applies a set of bones, then returns the deformed
+    vertices.
+
+    @param bones      The bones to apply.
+    @param boneCount  The number of bones.
+    @return           The transformed SkVertices.
+*/
+sk_sp<SkVertices> SkVertices::applyBones(const SkVertices::Bone bones[], int boneCount) const {
+    // If there aren't any bones, then nothing changes.
+    // We don't check if the SkVertices object has bone indices/weights because there is the case
+    // where the object can have no indices/weights but still have a world transform applied.
+    if (!bones || !boneCount) {
+        return sk_ref_sp(this);
+    }
+    SkASSERT(boneCount >= 1);
+
+    // Copy the SkVertices.
+    sk_sp<SkVertices> copy = SkVertices::MakeCopy(this->mode(),
+                                                  this->vertexCount(),
+                                                  this->positions(),
+                                                  this->texCoords(),
+                                                  this->colors(),
+                                                  nullptr,
+                                                  nullptr,
+                                                  this->indexCount(),
+                                                  this->indices());
+
+    // Transform the positions.
+    for (int i = 0; i < this->vertexCount(); i++) {
+        SkPoint& position = copy->fPositions[i];
+
+        // Apply the world transform.
+        position = bones[0].mapPoint(position);
+
+        // Apply the bone deformations.
+        if (boneCount > 1) {
+            SkASSERT(this->boneIndices());
+            SkASSERT(this->boneWeights());
+
+            SkPoint result = SkPoint::Make(0.0f, 0.0f);
+            const SkVertices::BoneIndices& indices = this->boneIndices()[i];
+            const SkVertices::BoneWeights& weights = this->boneWeights()[i];
+            for (int j = 0; j < 4; j++) {
+                int index = indices[j];
+                float weight = weights[j];
+                if (index == 0 || weight == 0.0f) {
+                    continue;
+                }
+                SkASSERT(index < boneCount);
+
+                // result += M * v * w.
+                result += bones[index].mapPoint(position) * weight;
+            }
+            position = result;
+        }
+    }
+
+    // Recalculate the bounds.
+    copy->fBounds.set(copy->fPositions, copy->fVertexCnt);
+
+    return copy;
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 027296c..9d61fb3 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -31,8 +31,9 @@
     kBonesAttribute_GPFlag          = 0x10,
 };
 
-static constexpr int kMaxBones = 80; // Due to GPU memory limitations, only up to 80 bone
-                                     // matrices are accepted.
+static constexpr int kNumVec2sPerBone = 3; // Our bone matrices are 3x2 matrices passed in as
+                                           // vec2s in column major order, and thus there are 3
+                                           // vec2s per bone.
 
 class DefaultGeoProc : public GrGeometryProcessor {
 public:
@@ -111,21 +112,36 @@
             }
 
             // Setup bone transforms
+            // NOTE: This code path is currently unused. Benchmarks have found that for all
+            // reasonable cases of skinned vertices, the overhead involved in copying and uploading
+            // bone data makes performing the transformations on the CPU faster than doing so on
+            // the GPU. This is being kept here in case that changes.
             const char* transformedPositionName = gp.fInPosition.name();
             if (gp.hasBones()) {
+                // Set up the uniform for the bones.
                 const char* vertBonesUniformName;
                 fBonesUniform = uniformHandler->addUniformArray(kVertex_GrShaderFlag,
-                                                                kFloat3x3_GrSLType,
+                                                                kFloat2_GrSLType,
                                                                 "Bones",
-                                                                kMaxBones,
+                                                                kMaxBones * kNumVec2sPerBone,
                                                                 &vertBonesUniformName);
+
+                // Set up the bone application function.
+                SkString applyBoneFunctionName;
+                this->emitApplyBoneFunction(vertBuilder,
+                                            vertBonesUniformName,
+                                            &applyBoneFunctionName);
+
+                // Apply the world transform to the position first.
                 vertBuilder->codeAppendf(
-                        "float3 originalPosition = %s[0] * float3(%s, 1);"
-                        "float2 transformedPosition = float2(0);"
+                        "float2 worldPosition = %s(0, %s);"
+                        "float2 transformedPosition = float2(0, 0);"
                         "for (int i = 0; i < 4; i++) {",
-                        vertBonesUniformName,
+                        applyBoneFunctionName.c_str(),
                         gp.fInPosition.name());
 
+                // If the GPU supports unsigned integers, then we can read the index. Otherwise,
+                // we have to estimate it given the float representation.
                 if (args.fShaderCaps->unsignedSupport()) {
                     vertBuilder->codeAppendf(
                         "    byte index = %s[i];",
@@ -136,12 +152,13 @@
                         gp.fInBoneIndices.name());
                 }
 
+                // Get the weight and apply the transformation.
                 vertBuilder->codeAppendf(
                         "    float weight = %s[i];"
-                        "    transformedPosition += (%s[index] * originalPosition * weight).xy;"
+                        "    transformedPosition += %s(index, worldPosition) * weight;"
                         "}",
                         gp.fInBoneWeights.name(),
-                        vertBonesUniformName);
+                        applyBoneFunctionName.c_str());
                 transformedPositionName = "transformedPosition";
             }
 
@@ -228,11 +245,41 @@
             fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
 
             if (dgp.hasBones()) {
-                pdman.setMatrix3fv(fBonesUniform, dgp.boneCount(), dgp.bones());
+                pdman.set2fv(fBonesUniform, dgp.boneCount() * kNumVec2sPerBone, dgp.bones());
             }
         }
 
     private:
+        void emitApplyBoneFunction(GrGLSLVertexBuilder* vertBuilder,
+                                   const char* vertBonesUniformName,
+                                   SkString* funcName) {
+                // The bone matrices are passed in as 3x2 matrices in column-major order as groups
+                // of 3 float2s. This code takes those float2s and performs the matrix operation on
+                // a given matrix and float2.
+                static const GrShaderVar gApplyBoneArgs[] = {
+                    GrShaderVar("index", kByte_GrSLType),
+                    GrShaderVar("vec", kFloat2_GrSLType),
+                };
+                SkString body;
+                body.appendf(
+                    "    float2 c0 = %s[index * 3];"
+                    "    float2 c1 = %s[index * 3 + 1];"
+                    "    float2 c2 = %s[index * 3 + 2];"
+                    "    float x = c0.x * vec.x + c1.x * vec.y + c2.x;"
+                    "    float y = c0.y * vec.x + c1.y * vec.y + c2.y;"
+                    "    return float2(x, y);",
+                    vertBonesUniformName,
+                    vertBonesUniformName,
+                    vertBonesUniformName);
+                vertBuilder->emitFunction(kFloat2_GrSLType,
+                                          "applyBone",
+                                          SK_ARRAY_COUNT(gApplyBoneArgs),
+                                          gApplyBoneArgs,
+                                          body.c_str(),
+                                          funcName);
+        }
+
+    private:
         SkMatrix fViewMatrix;
         GrColor fColor;
         uint8_t fCoverage;
@@ -336,13 +383,13 @@
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
 
 #if GR_TEST_UTILS
-static constexpr int kNumFloatsPerSkMatrix = 9;
+static constexpr int kNumFloatsPerBone = 6;
 static constexpr int kTestBoneCount = 4;
-static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerSkMatrix] = {
-    1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-    1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-    1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-    1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerBone] = {
+    1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+    1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+    1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+    1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
 };
 
 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h
index 3c4bd8e..b5aef98 100644
--- a/src/gpu/GrDefaultGeoProcFactory.h
+++ b/src/gpu/GrDefaultGeoProcFactory.h
@@ -12,6 +12,8 @@
 #include "GrGeometryProcessor.h"
 #include "GrShaderCaps.h"
 
+constexpr int kMaxBones = 80; // Supports up to 80 bones per mesh.
+
 /*
  * A factory for creating default Geometry Processors which simply multiply position by the uniform
  * view matrix and wire through color, coverage, UV coords if requested.
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 787bf7c..9664109 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -839,7 +839,7 @@
                                          GrPaint&& paint,
                                          const SkMatrix& viewMatrix,
                                          sk_sp<SkVertices> vertices,
-                                         const SkMatrix bones[],
+                                         const SkVertices::Bone bones[],
                                          int boneCount,
                                          GrPrimitiveType* overridePrimType) {
     ASSERT_SINGLE_OWNER
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index b0756a0..808d442 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -215,7 +215,7 @@
                       GrPaint&& paint,
                       const SkMatrix& viewMatrix,
                       sk_sp<SkVertices> vertices,
-                      const SkMatrix bones[],
+                      const SkVertices::Bone bones[],
                       int boneCount,
                       GrPrimitiveType* overridePrimType = nullptr);
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 1fe2ae4..6c3bd0a 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1484,7 +1484,7 @@
 
 void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount,
                                     const SkPoint vertices[],
-                                    const SkMatrix bones[], int boneCount,
+                                    const SkVertices::Bone bones[], int boneCount,
                                     SkBlendMode bmode,
                                     const uint16_t indices[], int indexCount,
                                     const SkPaint& paint) {
@@ -1548,8 +1548,8 @@
                                        &primitiveType);
 }
 
-void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkMatrix bones[], int boneCount,
-                               SkBlendMode mode, const SkPaint& paint) {
+void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
+                               int boneCount, SkBlendMode mode, const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
 
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index a3233ad..555e25e 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -87,7 +87,7 @@
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint&) override;
     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
-    void drawVertices(const SkVertices*, const SkMatrix bones[], int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint&) override;
     void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
     void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
@@ -244,7 +244,7 @@
     void drawStrokedLine(const SkPoint pts[2], const SkPaint&);
 
     void wireframeVertices(SkVertices::VertexMode, int vertexCount, const SkPoint verts[],
-                           const SkMatrix bones[], int boneCount, SkBlendMode,
+                           const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                            const uint16_t indices[], int indexCount, const SkPaint&);
 
     static sk_sp<GrRenderTargetContext> MakeRenderTargetContext(GrContext*,
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index dd91452..04b537f 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -12,12 +12,10 @@
 #include "SkGr.h"
 #include "SkRectPriv.h"
 
-static constexpr int kNumFloatsPerSkMatrix = 9;
-
 std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrContext* context,
                                                  GrPaint&& paint,
                                                  sk_sp<SkVertices> vertices,
-                                                 const SkMatrix bones[],
+                                                 const SkVertices::Bone bones[],
                                                  int boneCount,
                                                  const SkMatrix& viewMatrix,
                                                  GrAAType aaType,
@@ -32,7 +30,7 @@
 }
 
 GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
-                                   sk_sp<SkVertices> vertices, const SkMatrix bones[],
+                                   sk_sp<SkVertices> vertices, const SkVertices::Bone bones[],
                                    int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
                                    sk_sp<GrColorSpaceXform> colorSpaceXform,
                                    const SkMatrix& viewMatrix)
@@ -51,26 +49,23 @@
     mesh.fColor = color;
     mesh.fViewMatrix = viewMatrix;
     mesh.fVertices = std::move(vertices);
-    if (bones) {
-        // Copy the bone data over in the format that the GPU would upload.
-        mesh.fBones.reserve(boneCount * kNumFloatsPerSkMatrix);
-        for (int i = 0; i < boneCount; i ++) {
-            const SkMatrix& matrix = bones[i];
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleX));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewY));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp0));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMSkewX));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMScaleY));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp1));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMTransX));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMTransY));
-            mesh.fBones.push_back(matrix.get(SkMatrix::kMPersp2));
-        }
-    }
     mesh.fIgnoreTexCoords = false;
     mesh.fIgnoreColors = false;
     mesh.fIgnoreBones = false;
 
+    if (mesh.fVertices->hasBones() && bones) {
+        // Perform the transformations on the CPU instead of the GPU.
+        mesh.fVertices = mesh.fVertices->applyBones(bones, boneCount);
+    } else {
+        if (bones && boneCount > 1) {
+            // NOTE: This should never be used. All bone transforms are being done on the CPU
+            // instead of the GPU.
+
+            // Copy the bone data.
+            fBones.assign(bones, bones + boneCount);
+        }
+    }
+
     fFlags = 0;
     if (mesh.hasPerVertexColors()) {
         fFlags |= kRequiresPerVertexColors_Flag;
@@ -85,7 +80,9 @@
     // Special case for meshes with a world transform but no bone weights.
     // These will be considered normal vertices draws without bones.
     if (!mesh.fVertices->hasBones() && boneCount == 1) {
-        mesh.fViewMatrix.preConcat(bones[0]);
+        SkMatrix worldTransform;
+        worldTransform.setAffine(bones[0].values);
+        mesh.fViewMatrix.preConcat(worldTransform);
     }
 
     IsZeroArea zeroArea;
@@ -101,7 +98,7 @@
         SkRect bounds = SkRect::MakeEmpty();
         const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds());
         for (int i = 1; i < boneCount; i++) {
-            const SkMatrix& matrix = bones[i];
+            const SkVertices::Bone& matrix = bones[i];
             bounds.join(matrix.mapRect(originalBounds));
         }
 
@@ -188,7 +185,9 @@
 
     const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
 
-    Bones bones(fMeshes[0].fBones.data(), fMeshes[0].fBones.size() / kNumFloatsPerSkMatrix);
+    // The bones are packed as 6 floats in column major order, so we can directly upload them to
+    // the GPU as groups of 3 vec2s.
+    Bones bones(reinterpret_cast<const float*>(fBones.data()), fBones.size());
     *hasBoneAttribute = this->hasBones();
 
     if (this->hasBones()) {
diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h
index 07227e0..fd40e461 100644
--- a/src/gpu/ops/GrDrawVerticesOp.h
+++ b/src/gpu/ops/GrDrawVerticesOp.h
@@ -38,16 +38,16 @@
     static std::unique_ptr<GrDrawOp> Make(GrContext* context,
                                           GrPaint&&,
                                           sk_sp<SkVertices>,
-                                          const SkMatrix bones[],
+                                          const SkVertices::Bone bones[],
                                           int boneCount,
                                           const SkMatrix& viewMatrix,
                                           GrAAType,
                                           sk_sp<GrColorSpaceXform>,
                                           GrPrimitiveType* overridePrimType = nullptr);
 
-    GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>, const SkMatrix bones[],
-                     int boneCount, GrPrimitiveType, GrAAType, sk_sp<GrColorSpaceXform>,
-                     const SkMatrix& viewMatrix);
+    GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>,
+                     const SkVertices::Bone bones[], int boneCount, GrPrimitiveType, GrAAType,
+                     sk_sp<GrColorSpaceXform>, const SkMatrix& viewMatrix);
 
     const char* name() const override { return "DrawVerticesOp"; }
 
@@ -103,7 +103,6 @@
     struct Mesh {
         GrColor fColor;  // Used if this->hasPerVertexColors() is false.
         sk_sp<SkVertices> fVertices;
-        std::vector<float> fBones; // Transformation matrices stored in GPU format.
         SkMatrix fViewMatrix;
         bool fIgnoreTexCoords;
         bool fIgnoreColors;
@@ -118,7 +117,7 @@
         }
 
         bool hasBones() const {
-            return fVertices->hasBones() && fBones.size() && !fIgnoreBones;
+            return fVertices->hasBones() && !fIgnoreBones;
         }
     };
 
@@ -152,6 +151,7 @@
 
     Helper fHelper;
     SkSTArray<1, Mesh, true> fMeshes;
+    std::vector<SkVertices::Bone> fBones; // Bone transformation matrices.
     // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore
     // the SkVertices mode (though fPrimitiveType may have been inferred from it).
     GrPrimitiveType fPrimitiveType;
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 8664e50..fb208f8 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1375,7 +1375,7 @@
     }
 }
 
-void SkPDFDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+void SkPDFDevice::drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode,
                                const SkPaint&) {
     if (this->hasEmptyClip()) {
         return;
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 9a91790..0197b5a 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -97,7 +97,7 @@
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint&) override { SkASSERT(false); }
     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
-    void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint&) override;
     void drawDevice(SkBaseDevice*, int x, int y,
                     const SkPaint&) override;
diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp
index 258160c..bf06579 100644
--- a/src/pipe/SkPipeCanvas.cpp
+++ b/src/pipe/SkPipeCanvas.cpp
@@ -728,7 +728,7 @@
     write_paint(writer, paint, kGeometry_PaintUsage);
 }
 
-void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
                                         int boneCount, SkBlendMode bmode, const SkPaint& paint) {
     unsigned extra = static_cast<unsigned>(bmode);
 
@@ -737,7 +737,7 @@
     // TODO: dedup vertices?
     writer.writeDataAsByteArray(vertices->encode().get());
     writer.write32(boneCount);
-    writer.write(bones, sizeof(SkMatrix) * boneCount);
+    writer.write(bones, sizeof(SkVertices::Bone) * boneCount);
     write_paint(writer, paint, kVertices_PaintUsage);
 }
 
diff --git a/src/pipe/SkPipeCanvas.h b/src/pipe/SkPipeCanvas.h
index b39f809..a679491 100644
--- a/src/pipe/SkPipeCanvas.h
+++ b/src/pipe/SkPipeCanvas.h
@@ -135,8 +135,8 @@
                          const SkPaint*) override;
     void onDrawImageLattice(const SkImage*, const Lattice& lattice, 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/src/pipe/SkPipeReader.cpp b/src/pipe/SkPipeReader.cpp
index 909276f..1d77779 100644
--- a/src/pipe/SkPipeReader.cpp
+++ b/src/pipe/SkPipeReader.cpp
@@ -567,7 +567,7 @@
         vertices = SkVertices::Decode(data->data(), data->size());
     }
     int boneCount = reader.read32();
-    const SkMatrix* bones = boneCount ? reader.skipT<SkMatrix>(boneCount) : nullptr;
+    const SkVertices::Bone* bones = boneCount ? reader.skipT<SkVertices::Bone>(boneCount) : nullptr;
     if (vertices) {
         canvas->drawVertices(vertices, bones, boneCount, bmode, read_paint(reader));
     }
diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp
index 1f7ec36..593fe40 100644
--- a/src/svg/SkSVGDevice.cpp
+++ b/src/svg/SkSVGDevice.cpp
@@ -1040,7 +1040,7 @@
     }
 }
 
-void SkSVGDevice::drawVertices(const SkVertices*, const SkMatrix*, int, SkBlendMode,
+void SkSVGDevice::drawVertices(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode,
                                const SkPaint&) {
     // todo
 }
diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h
index 452229d..e57ef36 100644
--- a/src/svg/SkSVGDevice.h
+++ b/src/svg/SkSVGDevice.h
@@ -42,7 +42,7 @@
     void drawTextOnPath(const void* text, size_t len,
                         const SkPath& path, const SkMatrix* matrix,
                         const SkPaint& paint) override;
-    void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint& paint) override;
 
     void drawDevice(SkBaseDevice*, int x, int y,
diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp
index 441857f..edef7e3 100644
--- a/src/utils/SkLuaCanvas.cpp
+++ b/src/utils/SkLuaCanvas.cpp
@@ -314,8 +314,8 @@
     this->INHERITED::onDrawDrawable(drawable, matrix);
 }
 
-void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, const SkMatrix*, int, SkBlendMode,
-                                       const SkPaint& paint) {
+void SkLuaCanvas::onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int,
+                                       SkBlendMode, const SkPaint& paint) {
     AUTO_LUA("drawVertices");
     lua.pushPaint(paint, "paint");
 }
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index 7d1e981..ac3a971 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -320,7 +320,7 @@
     }
 }
 
-void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
+void SkNWayCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
                                         int boneCount, SkBlendMode bmode, const SkPaint& paint) {
     Iter iter(fList);
     while (iter.next()) {
diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp
index 929488c..862bca7 100644
--- a/src/utils/SkPaintFilterCanvas.cpp
+++ b/src/utils/SkPaintFilterCanvas.cpp
@@ -173,9 +173,9 @@
     }
 }
 
-void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
-                                               int boneCount, SkBlendMode bmode,
-                                               const SkPaint& paint) {
+void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices,
+                                               const SkVertices::Bone bones[], int boneCount,
+                                               SkBlendMode bmode, const SkPaint& paint) {
     AutoPaintFilter apf(this, kVertices_Type, paint);
     if (apf.shouldDraw()) {
         this->SkNWayCanvas::onDrawVerticesObject(vertices, bones, boneCount, bmode, *apf.paint());
diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp
index ff66e3b..e73b726 100644
--- a/src/xps/SkXPSDevice.cpp
+++ b/src/xps/SkXPSDevice.cpp
@@ -1156,7 +1156,7 @@
     draw(this, &SkDraw::drawPoints, mode, count, points, paint, this);
 }
 
-void SkXPSDevice::drawVertices(const SkVertices* v, const SkMatrix* bones, int boneCount,
+void SkXPSDevice::drawVertices(const SkVertices* v, const SkVertices::Bone bones[], int boneCount,
                                SkBlendMode blendMode, const SkPaint& paint) {
     draw(this, &SkDraw::drawVertices, v->mode(), v->vertexCount(), v->positions(), v->texCoords(),
          v->colors(), v->boneIndices(), v->boneWeights(), blendMode, v->indices(), v->indexCount(),
diff --git a/src/xps/SkXPSDevice.h b/src/xps/SkXPSDevice.h
index c3f27c4..877eb3b 100644
--- a/src/xps/SkXPSDevice.h
+++ b/src/xps/SkXPSDevice.h
@@ -99,7 +99,7 @@
     void drawPosText(const void* text, size_t len,
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint& paint) override;
-    void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
+    void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
                       const SkPaint&) override;
     void drawDevice(SkBaseDevice*, int x, int y,
                     const SkPaint&) override;