Rewrite GrQuad to use separate arrays of x and y values to be Sk4f friendly.

Change-Id: Ie2ad197c5f17849fe6e034b60bc7ec18a00edb24
Reviewed-on: https://skia-review.googlesource.com/128842
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index a495c55..6742232 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -146,6 +146,7 @@
   "$_src/gpu/GrProcessorUnitTest.h",
   "$_src/gpu/GrProxyProvider.cpp",
   "$_src/gpu/GrProxyProvider.h",
+  "$_src/gpu/GrQuad.cpp",
   "$_src/gpu/GrQuad.h",
   "$_src/gpu/GrRect.h",
   "$_src/gpu/GrRectanizer.h",
diff --git a/src/core/SkMatrixPriv.h b/src/core/SkMatrixPriv.h
index 9422fcc..9d76179 100644
--- a/src/core/SkMatrixPriv.h
+++ b/src/core/SkMatrixPriv.h
@@ -146,34 +146,6 @@
     static void MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[], size_t dstStride,
                                                const SkPoint3 src[], size_t srcStride, int count);
 
-    static void SetMappedRectTriStrip(const SkMatrix& mx, const SkRect& rect, SkPoint quad[4]) {
-        SkMatrix::TypeMask tm = mx.getType();
-        SkScalar l = rect.fLeft;
-        SkScalar t = rect.fTop;
-        SkScalar r = rect.fRight;
-        SkScalar b = rect.fBottom;
-        if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
-            const SkScalar tx = mx.getTranslateX();
-            const SkScalar ty = mx.getTranslateY();
-            if (tm <= SkMatrix::kTranslate_Mask) {
-                l += tx;
-                t += ty;
-                r += tx;
-                b += ty;
-            } else {
-                const SkScalar sx = mx.getScaleX();
-                const SkScalar sy = mx.getScaleY();
-                l = sx * l + tx;
-                t = sy * t + ty;
-                r = sx * r + tx;
-                b = sy * b + ty;
-            }
-           SkPointPriv::SetRectTriStrip(quad, l, t, r, b, sizeof(SkPoint));
-        } else {
-            SkPointPriv::SetRectTriStrip(quad, l, t, r, b, sizeof(SkPoint));
-            mx.mapPoints(quad, quad, 4);
-        }
-    }
 };
 
 #endif
diff --git a/src/gpu/GrQuad.cpp b/src/gpu/GrQuad.cpp
new file mode 100644
index 0000000..724a827
--- /dev/null
+++ b/src/gpu/GrQuad.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrQuad.h"
+
+GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
+    SkMatrix::TypeMask tm = m.getType();
+    if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
+        auto r = Sk4f::Load(&rect);
+        const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
+        if (tm <= SkMatrix::kTranslate_Mask) {
+            r += t;
+        } else {
+            const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
+            r = r * s + t;
+        }
+        SkNx_shuffle<0, 0, 2, 2>(r).store(fX);
+        SkNx_shuffle<1, 3, 1, 3>(r).store(fY);
+    } else {
+        Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
+        Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
+        Sk4f sx(m.getScaleX());
+        Sk4f kx(m.getSkewX());
+        Sk4f tx(m.getTranslateX());
+        Sk4f ky(m.getSkewY());
+        Sk4f sy(m.getScaleY());
+        Sk4f ty(m.getTranslateY());
+        auto x = SkNx_fma(sx, rx, SkNx_fma(kx, ry, tx));
+        auto y = SkNx_fma(ky, rx, SkNx_fma(sy, ry, ty));
+        if (m.hasPerspective()) {
+            Sk4f w0(m.getPerspX());
+            Sk4f w1(m.getPerspY());
+            Sk4f w2(m.get(SkMatrix::kMPersp2));
+            auto iw = SkNx_fma(w0, rx, SkNx_fma(w1, ry, w2)).invert();
+            x *= iw;
+            y *= iw;
+        }
+        x.store(fX);
+        y.store(fY);
+    }
+}
diff --git a/src/gpu/GrQuad.h b/src/gpu/GrQuad.h
index ca51f64..62f025d 100644
--- a/src/gpu/GrQuad.h
+++ b/src/gpu/GrQuad.h
@@ -8,9 +8,9 @@
 #ifndef GrQuad_DEFINED
 #define GrQuad_DEFINED
 
-#include "SkPoint.h"
 #include "SkMatrix.h"
-#include "SkMatrixPriv.h"
+#include "SkNx.h"
+#include "SkPoint.h"
 
 /**
  * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
@@ -18,50 +18,39 @@
  */
 class GrQuad {
 public:
-    GrQuad() {}
+    GrQuad() = default;
 
-    GrQuad(const GrQuad& that) {
-        *this = that;
+    GrQuad(const GrQuad& that) = default;
+
+    explicit GrQuad(const SkRect& rect)
+            : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
+            , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {}
+
+    /** Sets the quad to the rect as transformed by the matrix. */
+    GrQuad(const SkRect&, const SkMatrix&);
+
+    explicit GrQuad(const SkPoint pts[4])
+            : fX{pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX}
+            , fY{pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY} {}
+
+    GrQuad& operator=(const GrQuad& that) = default;
+
+    SkPoint point(int i) const { return {fX[i], fY[i]}; }
+
+    SkRect bounds() const {
+        auto x = this->x4f(), y = this->y4f();
+        return {x.min(), y.min(), x.max(), y.max()};
     }
 
-    explicit GrQuad(const SkRect& rect) {
-        this->set(rect);
-    }
+    float x(int i) const { return fX[i]; }
+    float y(int i) const { return fY[i]; }
 
-    void set(const SkRect& rect) {
-        SkPointPriv::SetRectTriStrip(fPoints, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
-                sizeof(SkPoint));
-    }
-
-    void map(const SkMatrix& matrix) {
-        matrix.mapPoints(fPoints, kNumPoints);
-    }
-
-    void setFromMappedRect(const SkRect& rect, const SkMatrix& matrix) {
-        SkMatrixPriv::SetMappedRectTriStrip(matrix, rect, fPoints);
-    }
-
-    const GrQuad& operator=(const GrQuad& that) {
-        memcpy(fPoints, that.fPoints, sizeof(SkPoint) * kNumPoints);
-        return *this;
-    }
-
-    SkPoint* points() {
-        return fPoints;
-    }
-
-    const SkPoint* points() const {
-        return fPoints;
-    }
-
-    const SkPoint& point(int i) const {
-        SkASSERT(i < kNumPoints);
-        return fPoints[i];
-    }
+    Sk4f x4f() const { return Sk4f::Load(fX); }
+    Sk4f y4f() const { return Sk4f::Load(fY); }
 
 private:
-    static const int kNumPoints = 4;
-    SkPoint fPoints[kNumPoints];
+    float fX[4];
+    float fY[4];
 };
 
 #endif
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index c447a5c..ded5049 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -512,8 +512,7 @@
                 return;
             }
             // Does the rect bound the RT?
-            GrQuad quad;
-            quad.setFromMappedRect(rtRect, invM);
+            GrQuad quad(rtRect, invM);
             if (rect_contains_inclusive(rect, quad.point(0)) &&
                 rect_contains_inclusive(rect, quad.point(1)) &&
                 rect_contains_inclusive(rect, quad.point(2)) &&
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index b815bf0..6386891 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -127,13 +127,13 @@
         info.fViewMatrix = viewMatrix;
         info.fRect = rect;
         if (localRect && localMatrix) {
-            info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
+            info.fLocalQuad = GrQuad(*localRect, *localMatrix);
         } else if (localRect) {
-            info.fLocalQuad.set(*localRect);
+            info.fLocalQuad = GrQuad(*localRect);
         } else if (localMatrix) {
-            info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
+            info.fLocalQuad = GrQuad(rect, *localMatrix);
         } else {
-            info.fLocalQuad.set(rect);
+            info.fLocalQuad = GrQuad(rect);
         }
         this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
     }
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 003d99a..3e21348 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -17,6 +17,7 @@
 #include "SkAutoMalloc.h"
 #include "SkAutoPixmapStorage.h"
 #include "SkDistanceFieldGen.h"
+#include "SkPointPriv.h"
 #include "SkRasterClip.h"
 #include "effects/GrBitmapTextGeoProc.h"
 #include "effects/GrDistanceFieldGeoProc.h"
@@ -743,8 +744,7 @@
         // vertex positions
         // TODO make the vertex attributes a struct
         if (fUsesDistanceField && !ctm.hasPerspective()) {
-            GrQuad quad;
-            quad.setFromMappedRect(translatedBounds, ctm);
+            GrQuad quad(translatedBounds, ctm);
             intptr_t positionOffset = offset;
             SkPoint* position = (SkPoint*)positionOffset;
             *position = quad.point(0);
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 926bd54..a4b79ac 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -20,6 +20,7 @@
 #include "GrTextureProxy.h"
 #include "SkGr.h"
 #include "SkMathPriv.h"
+#include "SkMatrixPriv.h"
 #include "SkPoint.h"
 #include "SkPoint3.h"
 #include "glsl/GrGLSLColorSpaceXformHelper.h"
@@ -311,8 +312,8 @@
         // as the intersection points of the outset edges.
 
         // GrQuad is in tristip order but we want the points to be in a fan order, so swap 2 and 3.
-        Sk4f xs(quad.point(0).fX, quad.point(1).fX, quad.point(3).fX, quad.point(2).fX);
-        Sk4f ys(quad.point(0).fY, quad.point(1).fY, quad.point(3).fY, quad.point(2).fY);
+        Sk4f xs = SkNx_shuffle<0, 1, 3, 2>(quad.x4f());
+        Sk4f ys = SkNx_shuffle<0, 1, 3, 2>(quad.y4f());
         Sk4f xsrot = SkNx_shuffle<1, 2, 3, 0>(xs);
         Sk4f ysrot = SkNx_shuffle<1, 2, 3, 0>(ys);
         Sk4f normXs = ysrot - ys;
@@ -365,9 +366,9 @@
 
 private:
     static void AssignTexCoords(Vertex* vertices, const GrQuad& quad, const SkRect& tex) {
-        SkMatrix q = SkMatrix::MakeAll(quad.point(0).fX, quad.point(1).fX, quad.point(2).fX,
-                                       quad.point(0).fY, quad.point(1).fY, quad.point(2).fY,
-                                                    1.f,              1.f,              1.f);
+        SkMatrix q = SkMatrix::MakeAll(quad.x(0), quad.x(1), quad.x(2),
+                                       quad.y(0), quad.y(1), quad.y(2),
+                                             1.f,       1.f,       1.f);
         SkMatrix qinv;
         if (!q.invert(&qinv)) {
             return;
@@ -474,10 +475,10 @@
                     "%d: Color: 0x%08x, ProxyIdx: %d, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
                     "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
                     i, draw.fColor, draw.fTextureIdx, draw.fSrcRect.fLeft, draw.fSrcRect.fTop,
-                    draw.fSrcRect.fRight, draw.fSrcRect.fBottom, draw.fQuad.points()[0].fX,
-                    draw.fQuad.points()[0].fY, draw.fQuad.points()[1].fX, draw.fQuad.points()[1].fY,
-                    draw.fQuad.points()[2].fX, draw.fQuad.points()[2].fY, draw.fQuad.points()[3].fX,
-                    draw.fQuad.points()[3].fY);
+                    draw.fSrcRect.fRight, draw.fSrcRect.fBottom, draw.fQuad.point(0).fX,
+                    draw.fQuad.point(0).fY, draw.fQuad.point(1).fX, draw.fQuad.point(1).fY,
+                    draw.fQuad.point(2).fX, draw.fQuad.point(2).fY, draw.fQuad.point(3).fX,
+                    draw.fQuad.point(3).fY);
         }
         str += INHERITED::dumpInfo();
         return str;
@@ -529,9 +530,8 @@
         draw.fSrcRect = srcRect;
         draw.fTextureIdx = 0;
         draw.fColor = color;
-        draw.fQuad.setFromMappedRect(dstRect, viewMatrix);
-        SkRect bounds;
-        bounds.setBounds(draw.fQuad.points(), 4);
+        draw.fQuad = GrQuad(dstRect, viewMatrix);
+        SkRect bounds = draw.fQuad.bounds();
         this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
 
         fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds);
diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp
index 73ac5f1..a503bc3 100644
--- a/tests/OnFlushCallbackTest.cpp
+++ b/tests/OnFlushCallbackTest.cpp
@@ -55,7 +55,7 @@
             , fRect(r)
             , fHelper(helperArgs, GrAAType::kNone) {
         if (fHasLocalRect) {
-            fLocalQuad.set(*localRect);
+            fLocalQuad = GrQuad(*localRect);
         }
         // Choose some conservative values for aa bloat and zero area.
         this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
@@ -140,7 +140,7 @@
         // Setup positions
         SkPoint* position = (SkPoint*) vertices;
         SkPointPriv::SetRectTriStrip(position, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
-                                  vertexStride);
+                                     vertexStride);
 
         // Setup vertex colors
         GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
@@ -210,7 +210,7 @@
     void setColor(GrColor color) { fColor = color; }
     void setLocalRect(const SkRect& localRect) {
         SkASSERT(fHasLocalRect);    // This should've been created to anticipate this
-        fLocalQuad.set(localRect);
+        fLocalQuad = GrQuad(localRect);
     }
 
     AtlasedRectOp* next() const { return fNext; }