summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2009-01-30 03:40:16 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2009-01-30 03:40:16 +0000
commit78409ff50c16d89ba5931f0a57b45ac1f5367573 (patch)
tree4dce5108bc83e49a1b1f72ec098e61b39f01513d /apps/plugins
parent8751b94e48dcb6cb72bd916b5a7b2c23d7410cdf (diff)
remove 64-bit math from fdiv in pictureflow.c, replacing it with limited pre-shifting of input values
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19886 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/pictureflow.c71
1 files changed, 63 insertions, 8 deletions
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index 665ef9576f..025d1e6be2 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -337,17 +337,73 @@ static inline PFreal fmul(PFreal a, PFreal b)
return (a*b) >> PFREAL_SHIFT;
}
-/* There are some precision issues when not using (long long) which in turn
- takes very long to compute... I guess the best solution would be to optimize
- the computations so it only requires a single long */
-static inline PFreal fdiv(PFreal num, PFreal den)
+/* ARMv5+ have a clz instruction. So do most modern desktop processors, and the
+ * simulator doesn't need to be as concerned about savings for inlining a calls
+ * to a clz function.
+ */
+#if defined(SIMULATOR) || (defined(CPU_ARM) && (ARM_ARCH > 4))
+static inline int clz(uint32_t v)
{
- long long p = (long long) (num) << (PFREAL_SHIFT * 2);
- long long q = p / (long long) den;
- long long r = q >> PFREAL_SHIFT;
+ return __builtin_clz(v);
+}
+/* Otherwise, use our clz, which can be inlined */
+#else
+/* This clz is based on the log2(n) implementation at
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+ */
+static inline int clz(uint32_t v)
+{
+ uint32_t r = 31;
+ if (v > 0x8000)
+ {
+ v >>= 16;
+ r -= 16;
+ }
+ if (v & 0xff00)
+ {
+ v >>= 8;
+ r -= 8;
+ }
+ if (v & 0xf0)
+ {
+ v >>= 4;
+ r -= 4;
+ }
+ if (v & 0xc)
+ {
+ v >>= 2;
+ r -= 2;
+ }
+ if (v & 2)
+ r -= 1;
return r;
}
+#endif
+
+/* Return the maximum possible left shift for a signed int32, without
+ * overflow
+ */
+static inline int allowed_shift(int32_t val)
+{
+ uint32_t uval = val ^ (val >> 31);
+ if (!uval)
+ return 31;
+ else
+ return clz(uval) - 1;
+}
+
+/* Calculate num/den, with the result shifted left by PFREAL_SHIFT, by shifting
+ * num and den before dividing.
+ */
+static inline PFreal fdiv(PFreal num, PFreal den)
+{
+ int shift = allowed_shift(num);
+ shift = MIN(PFREAL_SHIFT, shift);
+ num <<= shift;
+ den >>= PFREAL_SHIFT - shift;
+ return num / den;
+}
#define fmin(a,b) (((a) < (b)) ? (a) : (b))
#define fmax(a,b) (((a) > (b)) ? (a) : (b))
@@ -579,7 +635,6 @@ int create_track_index(const int slide_index)
return (track_count > 0) ? 0 : -1;
}
-
/**
Determine filename of the album art for the given slide_index and
store the result in buf.