Title: [267276] branches/safari-610-branch/Source/WebCore
Revision
267276
Author
[email protected]
Date
2020-09-18 12:36:39 -0700 (Fri, 18 Sep 2020)

Log Message

Cherry-pick r266619. rdar://problem/69101154

    Add a fast path in TransformationMatrix::mapRect(const FloatRect&) for affine transformations
    https://bugs.webkit.org/show_bug.cgi?id=216139

    Reviewed by Tim Horton.

    Add a fast path when mapping 2D points through affine transformation matrices that takes advantage of both:
    1.  The predetermined 0 and 1 values in affine transformation matrices.
    2.  The fact that points in the FloatRect are aligned with x and y axes (as opposed to a FloatQuad of 4 arbitrary
        points), which allows us to avoid mapping all 4 corners of the rect through the matrix.

    The current implementation of this method maps each of the 4 corners through the transformation matrix, creates
    a FloatQuad using these 4 transformed points, and then asks the FloatQuad for its bounding box. This requires
    a total of 26 floating point additions, 24 multiplications and 20 comparisons, as well as a small (but
    measurable) amount of overhead when creating the FloatPoints and FloatQuad and asking for the bounding rect.

    We can pare this down to just 8 additions, 8 multiplications, and 4 comparisons by using a different strategy
    that instead branches on the 4 relevant matrix coefficients `a, b, c, d` (rather than the each of the final x
    and y coordinates) to determine which of the min or max x and y values to multiply in order to compute the min
    and max x and y coordinates in the final bounding rect.

    In a quick microbenchmark that maps FloatRects through an affine TransformationMatrix, this roughly halves the
    time spent in `TransformationMatrix::mapRect`; on the Multiply subtest of MotionMark (which invokes this method
    ~17 million times, almost entirely with affine transformation matrices), I measured a ~1% improvement.

    * platform/graphics/transforms/TransformationMatrix.cpp:
    (WebCore::TransformationMatrix::mapRect const):

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@266619 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Diff

Modified: branches/safari-610-branch/Source/WebCore/ChangeLog (267275 => 267276)


--- branches/safari-610-branch/Source/WebCore/ChangeLog	2020-09-18 19:36:37 UTC (rev 267275)
+++ branches/safari-610-branch/Source/WebCore/ChangeLog	2020-09-18 19:36:39 UTC (rev 267276)
@@ -1,5 +1,68 @@
 2020-09-18  Alan Coon  <[email protected]>
 
+        Cherry-pick r266619. rdar://problem/69101154
+
+    Add a fast path in TransformationMatrix::mapRect(const FloatRect&) for affine transformations
+    https://bugs.webkit.org/show_bug.cgi?id=216139
+    
+    Reviewed by Tim Horton.
+    
+    Add a fast path when mapping 2D points through affine transformation matrices that takes advantage of both:
+    1.  The predetermined 0 and 1 values in affine transformation matrices.
+    2.  The fact that points in the FloatRect are aligned with x and y axes (as opposed to a FloatQuad of 4 arbitrary
+        points), which allows us to avoid mapping all 4 corners of the rect through the matrix.
+    
+    The current implementation of this method maps each of the 4 corners through the transformation matrix, creates
+    a FloatQuad using these 4 transformed points, and then asks the FloatQuad for its bounding box. This requires
+    a total of 26 floating point additions, 24 multiplications and 20 comparisons, as well as a small (but
+    measurable) amount of overhead when creating the FloatPoints and FloatQuad and asking for the bounding rect.
+    
+    We can pare this down to just 8 additions, 8 multiplications, and 4 comparisons by using a different strategy
+    that instead branches on the 4 relevant matrix coefficients `a, b, c, d` (rather than the each of the final x
+    and y coordinates) to determine which of the min or max x and y values to multiply in order to compute the min
+    and max x and y coordinates in the final bounding rect.
+    
+    In a quick microbenchmark that maps FloatRects through an affine TransformationMatrix, this roughly halves the
+    time spent in `TransformationMatrix::mapRect`; on the Multiply subtest of MotionMark (which invokes this method
+    ~17 million times, almost entirely with affine transformation matrices), I measured a ~1% improvement.
+    
+    * platform/graphics/transforms/TransformationMatrix.cpp:
+    (WebCore::TransformationMatrix::mapRect const):
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@266619 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-09-04  Wenson Hsieh  <[email protected]>
+
+            Add a fast path in TransformationMatrix::mapRect(const FloatRect&) for affine transformations
+            https://bugs.webkit.org/show_bug.cgi?id=216139
+
+            Reviewed by Tim Horton.
+
+            Add a fast path when mapping 2D points through affine transformation matrices that takes advantage of both:
+            1.  The predetermined 0 and 1 values in affine transformation matrices.
+            2.  The fact that points in the FloatRect are aligned with x and y axes (as opposed to a FloatQuad of 4 arbitrary
+                points), which allows us to avoid mapping all 4 corners of the rect through the matrix.
+
+            The current implementation of this method maps each of the 4 corners through the transformation matrix, creates
+            a FloatQuad using these 4 transformed points, and then asks the FloatQuad for its bounding box. This requires
+            a total of 26 floating point additions, 24 multiplications and 20 comparisons, as well as a small (but
+            measurable) amount of overhead when creating the FloatPoints and FloatQuad and asking for the bounding rect.
+
+            We can pare this down to just 8 additions, 8 multiplications, and 4 comparisons by using a different strategy
+            that instead branches on the 4 relevant matrix coefficients `a, b, c, d` (rather than the each of the final x
+            and y coordinates) to determine which of the min or max x and y values to multiply in order to compute the min
+            and max x and y coordinates in the final bounding rect.
+
+            In a quick microbenchmark that maps FloatRects through an affine TransformationMatrix, this roughly halves the
+            time spent in `TransformationMatrix::mapRect`; on the Multiply subtest of MotionMark (which invokes this method
+            ~17 million times, almost entirely with affine transformation matrices), I measured a ~1% improvement.
+
+            * platform/graphics/transforms/TransformationMatrix.cpp:
+            (WebCore::TransformationMatrix::mapRect const):
+
+2020-09-18  Alan Coon  <[email protected]>
+
         Cherry-pick r266513. rdar://problem/69153717
 
     Make TransformationMatrix::inverse() faster in the case of affine transformation matrices

Modified: branches/safari-610-branch/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp (267275 => 267276)


--- branches/safari-610-branch/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2020-09-18 19:36:37 UTC (rev 267275)
+++ branches/safari-610-branch/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2020-09-18 19:36:39 UTC (rev 267276)
@@ -751,20 +751,70 @@
 
 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
 {
-    if (isIdentityOrTranslation()) {
+    auto type = this->type();
+    if (type == Type::IdentityOrTranslation) {
         FloatRect mappedRect(r);
         mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
         return mappedRect;
     }
 
+    float minX = r.x();
+    float minY = r.y();
+    float maxX = r.maxX();
+    float maxY = r.maxY();
+
+    if (type == Type::Affine) {
+        double a = m11();
+        double b = m12();
+        double c = m21();
+        double d = m22();
+
+        double minResultX;
+        double minResultY;
+        double maxResultX;
+        double maxResultY;
+
+        if (a > 0) {
+            maxResultX = a * maxX;
+            minResultX = a * minX;
+        } else {
+            maxResultX = a * minX;
+            minResultX = a * maxX;
+        }
+
+        if (b > 0) {
+            maxResultY = b * maxX;
+            minResultY = b * minX;
+        } else {
+            maxResultY = b * minX;
+            minResultY = b * maxX;
+        }
+
+        if (c > 0) {
+            maxResultX += c * maxY;
+            minResultX += c * minY;
+        } else {
+            maxResultX += c * minY;
+            minResultX += c * maxY;
+        }
+
+        if (d > 0) {
+            maxResultY += d * maxY;
+            minResultY += d * minY;
+        } else {
+            maxResultY += d * minY;
+            minResultY += d * maxY;
+        }
+
+        return FloatRect(minResultX + m41(), minResultY + m42(), maxResultX - minResultX, maxResultY - minResultY);
+    }
+
     FloatQuad result;
 
-    float maxX = r.maxX();
-    float maxY = r.maxY();
-    result.setP1(internalMapPoint(FloatPoint(r.x(), r.y())));
-    result.setP2(internalMapPoint(FloatPoint(maxX, r.y())));
+    result.setP1(internalMapPoint(FloatPoint(minX, minY)));
+    result.setP2(internalMapPoint(FloatPoint(maxX, minY)));
     result.setP3(internalMapPoint(FloatPoint(maxX, maxY)));
-    result.setP4(internalMapPoint(FloatPoint(r.x(), maxY)));
+    result.setP4(internalMapPoint(FloatPoint(minX, maxY)));
 
     return result.boundingBox();
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to