Runtime CPU detection for rsqrt().
authormtklein <mtklein@chromium.org>
Thu, 30 Jul 2015 16:29:37 +0000 (09:29 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 30 Jul 2015 16:29:37 +0000 (09:29 -0700)
This enables the NEON sk_float_rsqrt() code for configurations that have NEON at run-time but not compile-time.

These devices will see about a 2x (1.26 -> 2.33) slowdown in sk_float_rsqrt(), but it should be more precise than our portable fallback.

(When inlined, the portable fallback and the NEON code are almost identical in speed.  The only difference is precision.  Going through a function pointer is causing all this slowdown.  This is a good example of a place where Skia really benefits from compile-time NEON.)

BUG=skia:4117,skia:4114

No public API changes.
TBR=reed@google.com

Review URL: https://codereview.chromium.org/1264893002

include/core/SkFloatingPoint.h
src/core/SkOpts.cpp
src/core/SkOpts.h
src/opts/SkOpts_neon.cpp

index 73eb26c0dbb1c96aa3d669f54f3db3ead2c674f1..5ca4d103d0bf160ff103812dc25b64b317f9c0c2 100644 (file)
@@ -127,6 +127,8 @@ extern const uint32_t gIEEENegativeInfinity;
 #define SK_FloatInfinity            (*SkTCast<const float*>(&gIEEEInfinity))
 #define SK_FloatNegativeInfinity    (*SkTCast<const float*>(&gIEEENegativeInfinity))
 
+namespace SkOpts { extern float (*rsqrt)(float); }
+
 // Fast, approximate inverse square root.
 // Compare to name-brand "1.0f / sk_float_sqrt(x)".  Should be around 10x faster on SSE, 2x on NEON.
 static inline float sk_float_rsqrt(const float x) {
@@ -149,15 +151,8 @@ static inline float sk_float_rsqrt(const float x) {
     estimate = vmul_f32(estimate, vrsqrts_f32(xx, estimate_sq));
     return vget_lane_f32(estimate, 0);  // 1 will work fine too; the answer's in both places.
 #else
-    // Get initial estimate.
-    int i = *SkTCast<int*>(&x);
-    i = 0x5F1FFFF9 - (i>>1);
-    float estimate = *SkTCast<float*>(&i);
-
-    // One step of Newton's method to refine.
-    const float estimate_sq = estimate*estimate;
-    estimate *= 0.703952253f*(2.38924456f-x*estimate_sq);
-    return estimate;
+    // Perhaps runtime-detected NEON, or a portable fallback.
+    return SkOpts::rsqrt(x);
 #endif
 }
 
index 4f7c5e9345ee2dd816090b252f565286d9872b28..7da306c99d538417eb2948210f1e2bc9629fa8cb 100644 (file)
     #include <cpu-features.h>
 #endif
 
+static float rsqrt_portable(float x) {
+    // Get initial estimate.
+    int i = *SkTCast<int*>(&x);
+    i = 0x5F1FFFF9 - (i>>1);
+    float estimate = *SkTCast<float*>(&i);
+
+    // One step of Newton's method to refine.
+    const float estimate_sq = estimate*estimate;
+    estimate *= 0.703952253f*(2.38924456f-x*estimate_sq);
+    return estimate;
+}
+
 namespace SkOpts {
-    // (Define default function pointer values here...)
+    // Define default function pointer values here...
+    decltype(rsqrt) rsqrt = rsqrt_portable;
 
     // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
     void Init_sse2();
index 71abae5d7a57c9b8a74631675ef32a3e98e590e7..f02ec97553519c06ec4356a9d2a7095a6e7d379b 100644 (file)
@@ -16,7 +16,10 @@ namespace SkOpts {
     // Called by SkGraphics::Init(), and automatically #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS.
     void Init();
 
-    // (Function pointers go here).
+    // Declare function pointers here...
+
+    // Returns a fast approximation of 1.0f/sqrtf(x).
+    extern float (*rsqrt)(float);
 }
 
 #endif//SkOpts_DEFINED
index 3508b3531852324b01ba937ad3f52dbc9ca97c2e..ef667dc065306f405044e04cc961af4d4cddf7c1 100644 (file)
@@ -6,9 +6,11 @@
  */
 
 #include "SkOpts.h"
+#include "SkFloatingPoint.h"
 
 namespace SkOpts {
     void Init_neon() {
+        rsqrt = sk_float_rsqrt;  // This copy of sk_float_rsqrt will take the NEON path.
 
     }
 }