From: reed@google.com Date: Tue, 6 Dec 2011 18:56:37 +0000 (+0000) Subject: rename hasValidCoordinates to isFinite (on SkRect) and reimplement for speed X-Git-Tag: submit/tizen/20180928.044319~17183 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1607863b608b7db6c813228768ed5d72997bbc82;p=platform%2Fupstream%2FlibSkiaSharp.git rename hasValidCoordinates to isFinite (on SkRect) and reimplement for speed git-svn-id: http://skia.googlecode.com/svn/trunk@2811 2bbb7eff-a529-9590-31e7-b0007b416f81 --- diff --git a/bench/MathBench.cpp b/bench/MathBench.cpp index 1644a9e200..ffee901545 100644 --- a/bench/MathBench.cpp +++ b/bench/MathBench.cpp @@ -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(&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); diff --git a/include/core/SkRect.h b/include/core/SkRect.h index 76c99df648..65e76116f0 100644 --- a/include/core/SkRect.h +++ b/include/core/SkRect.h @@ -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; } diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 70ee430bfb..f382893f8c 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -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()) { diff --git a/src/core/SkRect.cpp b/src/core/SkRect.cpp index fab1412715..5e3d93c339 100644 --- a/src/core/SkRect.cpp +++ b/src/core/SkRect.cpp @@ -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(fLeft, fRight); diff --git a/tests/InfRectTest.cpp b/tests/InfRectTest.cpp index a78eba6dac..12356d9c2f 100644 --- a/tests/InfRectTest.cpp +++ b/tests/InfRectTest.cpp @@ -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);