rename hasValidCoordinates to isFinite (on SkRect) and reimplement for speed
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 6 Dec 2011 18:56:37 +0000 (18:56 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 6 Dec 2011 18:56:37 +0000 (18:56 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@2811 2bbb7eff-a529-9590-31e7-b0007b416f81

bench/MathBench.cpp
include/core/SkRect.h
src/core/SkCanvas.cpp
src/core/SkRect.cpp
tests/InfRectTest.cpp

index 1644a9e2003d3f0463044a83ea989e5dafd82e21..ffee9015455bc1f01f2979a7a0897e4dedd5aa52 100644 (file)
@@ -3,6 +3,7 @@
 #include "SkMatrix.h"
 #include "SkRandom.h"
 #include "SkString.h"
+#include "SkPaint.h"
 
 class MathBench : public SkBenchmark {
     enum {
@@ -211,6 +212,21 @@ static const struct {
 
 #undef MAKEREC
 
+static bool SkScalarIsNaN_new(SkScalar x) {
+    float y = x * 0;
+    return y == y;
+}
+
+static bool isFinite(const SkRect& r) {
+    // x * 0 will be NaN iff x is infinity or NaN.
+    // a + b will be NaN iff either a or b is NaN.
+    float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
+    
+    // value is either NaN or it is finite (zero).
+    // value==value will be true iff value is not NaN
+    return value == value;
+}
+
 class IsFiniteBench : public SkBenchmark {
     enum {
         N = SkBENCHLOOP(1000),
@@ -225,20 +241,41 @@ public:
         for (int i = 0; i < N; ++i) {
             fData[i] = rand.nextSScalar1();
         }
-        
-        fProc = gRec[index].fProc;
-        fName = gRec[index].fName;
+
+        if (index < 0) {
+            fProc = NULL;
+            fName = "isfinite_rect";
+        } else {
+            fProc = gRec[index].fProc;
+            fName = gRec[index].fName;
+        }
     }
 
 protected:
     virtual void onDraw(SkCanvas* canvas) {
         IsFiniteProc proc = fProc;
         const float* data = fData;
-
-        for (int j = 0; j < NN; ++j) {
-            for (int i = 0; i < N - 4; ++i) {
-                proc(&data[i]);
+        // do this so the compiler won't throw away the function call
+        int counter = 0;
+
+        if (proc) {
+            for (int j = 0; j < NN; ++j) {
+                for (int i = 0; i < N - 4; ++i) {
+                    counter += proc(&data[i]);
+                }
             }
+        } else {
+            for (int j = 0; j < NN; ++j) {
+                for (int i = 0; i < N - 4; ++i) {
+                    const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
+                    counter += r->isFinite();
+                }
+            }
+        }
+        
+        SkPaint paint;
+        if (paint.getAlpha() == 0) {
+            SkDebugf("%d\n", counter);
         }
     }
 
@@ -261,6 +298,7 @@ static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
 static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
 static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
 
+static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
 static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
 static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
 static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
@@ -274,6 +312,7 @@ static BenchRegistry gReg2(M2);
 static BenchRegistry gReg3(M3);
 static BenchRegistry gReg4(M4);
 
+static BenchRegistry gReg5neg1(M5neg1);
 static BenchRegistry gReg50(M50);
 static BenchRegistry gReg51(M51);
 static BenchRegistry gReg52(M52);
index 76c99df648e1719e21480c9a1e479668a46ad48f..65e76116f01ee2e8d49fcc23e889b4c2ab938e9e 100644 (file)
@@ -335,10 +335,34 @@ struct SK_API SkRect {
         return r;
     }
 
-    /** Return true if the rectangle's width or height are <= 0
-    */
-    bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
-    bool        hasValidCoordinates() const;
+    /**
+     *  Return true if the rectangle's width or height are <= 0
+     */
+    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+    
+    /**
+     *  Returns true iff all values in the rect are finite. If any are
+     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
+     *  returns false.
+     */
+    bool isFinite() const {
+#ifdef SK_SCALAR_IS_FLOAT
+        // x * 0 will be NaN iff x is infinity or NaN.
+        // a + b will be NaN iff either a or b is NaN.
+        float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+        
+        // value is either NaN or it is finite (zero).
+        // value==value will be true iff value is not NaN
+        return value == value;
+#else
+        // use bit-or for speed, since we don't care about short-circuting the
+        // tests, and we expect the common case will be that we need to check all.
+        int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
+                    (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
+        return !isNaN;
+#endif
+    }
+
     SkScalar    left() const { return fLeft; }
     SkScalar    top() const { return fTop; }
     SkScalar    right() const { return fRight; }
index 70ee430bfb12578df268ec4fff2946f48696be33..f382893f8cf04c8a328825c2bb1424f47f62e517 100644 (file)
@@ -1068,7 +1068,7 @@ void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
  */
 bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
 
-    if (!rect.hasValidCoordinates())
+    if (!rect.isFinite())
         return true;
 
     if (fMCRec->fRasterClip->isEmpty()) {
index fab1412715b7f368b8c419654ab05bdbf9dfe503..5e3d93c339f4ffa81353b404219b01110b931fa4 100644 (file)
@@ -37,13 +37,6 @@ void SkIRect::sort() {
 
 /////////////////////////////////////////////////////////////////////////////
 
-bool SkRect::hasValidCoordinates() const {
-    return  SkScalarIsFinite(fLeft) &&
-            SkScalarIsFinite(fTop) &&
-            SkScalarIsFinite(fRight) &&
-            SkScalarIsFinite(fBottom);
-}
-
 void SkRect::sort() {
     if (fLeft > fRight) {
         SkTSwap<SkScalar>(fLeft, fRight);
index a78eba6dac0ea8496882e886a0ef4aff8f2302c1..12356d9c2f841b4ed90f19b0305c4d56368cf8ae 100644 (file)
@@ -18,10 +18,10 @@ static void check_invalid(skiatest::Reporter* reporter,
                           SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
     SkRect rect;
     rect.set(l, t, r, b);
-    REPORTER_ASSERT(reporter, !rect.hasValidCoordinates());
+    REPORTER_ASSERT(reporter, !rect.isFinite());
 }
 
-// Tests that hasValidCoordinates() will reject any rect with +/-inf values
+// Tests that isFinite() will reject any rect with +/-inf values
 // as one of its coordinates.
 static void TestInfRect(skiatest::Reporter* reporter) {
 #ifdef SK_SCALAR_IS_FLOAT
@@ -33,7 +33,7 @@ static void TestInfRect(skiatest::Reporter* reporter) {
     SkScalar big = SkIntToScalar(100);
 
     SkRect rect = SkRect::MakeXYWH(small, small, big, big);
-    REPORTER_ASSERT(reporter, rect.hasValidCoordinates());
+    REPORTER_ASSERT(reporter, rect.isFinite());
 
     check_invalid(reporter, small, small, big, invalid);
     check_invalid(reporter, small, small, invalid, big);