diff options
Diffstat (limited to 'include/private/pixelflinger/ggl_fixed.h')
-rw-r--r-- | include/private/pixelflinger/ggl_fixed.h | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/include/private/pixelflinger/ggl_fixed.h b/include/private/pixelflinger/ggl_fixed.h new file mode 100644 index 0000000..96fdb32 --- /dev/null +++ b/include/private/pixelflinger/ggl_fixed.h @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GGL_FIXED_H +#define ANDROID_GGL_FIXED_H + +#include <math.h> +#include <pixelflinger/pixelflinger.h> + +// ---------------------------------------------------------------------------- + +#define CONST __attribute__((const)) +#define ALWAYS_INLINE __attribute__((always_inline)) + +const GGLfixed FIXED_BITS = 16; +const GGLfixed FIXED_EPSILON = 1; +const GGLfixed FIXED_ONE = 1L<<FIXED_BITS; +const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1); +const GGLfixed FIXED_MIN = 0x80000000L; +const GGLfixed FIXED_MAX = 0x7FFFFFFFL; + +inline GGLfixed gglIntToFixed(GGLfixed i) ALWAYS_INLINE ; +inline GGLfixed gglFixedToIntRound(GGLfixed f) ALWAYS_INLINE ; +inline GGLfixed gglFixedToIntFloor(GGLfixed f) ALWAYS_INLINE ; +inline GGLfixed gglFixedToIntCeil(GGLfixed f) ALWAYS_INLINE ; +inline GGLfixed gglFracx(GGLfixed v) ALWAYS_INLINE ; +inline GGLfixed gglFloorx(GGLfixed v) ALWAYS_INLINE ; +inline GGLfixed gglCeilx(GGLfixed v) ALWAYS_INLINE ; +inline GGLfixed gglCenterx(GGLfixed v) ALWAYS_INLINE ; +inline GGLfixed gglRoundx(GGLfixed v) ALWAYS_INLINE ; + +GGLfixed gglIntToFixed(GGLfixed i) { + return i<<FIXED_BITS; +} +GGLfixed gglFixedToIntRound(GGLfixed f) { + return (f + FIXED_HALF)>>FIXED_BITS; +} +GGLfixed gglFixedToIntFloor(GGLfixed f) { + return f>>FIXED_BITS; +} +GGLfixed gglFixedToIntCeil(GGLfixed f) { + return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS; +} + +GGLfixed gglFracx(GGLfixed v) { + return v & ((1<<FIXED_BITS)-1); +} +GGLfixed gglFloorx(GGLfixed v) { + return gglFixedToIntFloor(v)<<FIXED_BITS; +} +GGLfixed gglCeilx(GGLfixed v) { + return gglFixedToIntCeil(v)<<FIXED_BITS; +} +GGLfixed gglCenterx(GGLfixed v) { + return gglFloorx(v + FIXED_HALF) | FIXED_HALF; +} +GGLfixed gglRoundx(GGLfixed v) { + return gglFixedToIntRound(v)<<FIXED_BITS; +} + +// conversion from (unsigned) int, short, byte to fixed... +#define GGL_B_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<10 ) +#define GGL_S_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<2 ) +#define GGL_I_TO_X(_x) GGLfixed( ((int32_t(_x)>>1)+1)>>14 ) +#define GGL_UB_TO_X(_x) GGLfixed( uint32_t(_x) + \ + (uint32_t(_x)<<8) + \ + (uint32_t(_x)>>7) ) +#define GGL_US_TO_X(_x) GGLfixed( (_x) + ((_x)>>15) ) +#define GGL_UI_TO_X(_x) GGLfixed( (((_x)>>1)+1)>>15 ) + +// ---------------------------------------------------------------------------- + +GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST; +GGLfixed gglSqrtx(GGLfixed a) CONST; +GGLfixed gglSqrtRecipx(GGLfixed x) CONST; +GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST; +int32_t gglMulDivi(int32_t a, int32_t b, int32_t c); + +int32_t gglRecipQNormalized(int32_t x, int* exponent); +int32_t gglRecipQ(GGLfixed x, int q) CONST; + +inline GGLfixed gglRecip(GGLfixed x) CONST; +inline GGLfixed gglRecip(GGLfixed x) { + return gglRecipQ(x, 16); +} + +inline GGLfixed gglRecip28(GGLfixed x) CONST; +int32_t gglRecip28(GGLfixed x) { + return gglRecipQ(x, 28); +} + +// ---------------------------------------------------------------------------- + +#if defined(__arm__) && !defined(__thumb__) + +// inline ARM implementations +inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST; +inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) { + GGLfixed result, t; + if (__builtin_constant_p(shift)) { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "movs %[lo], %[lo], lsr %[rshift] \n" + "adc %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=r"(result), [hi]"=r"(t), [x]"=r"(x) + : "%[x]"(x), [y]"r"(y), [lshift] "I"(32-shift), [rshift] "I"(shift) + : "cc" + ); + } else { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "movs %[lo], %[lo], lsr %[rshift] \n" + "adc %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x) + : "%[x]"(x), [y]"r"(y), [lshift] "r"(32-shift), [rshift] "r"(shift) + : "cc" + ); + } + return result; +} + +inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST; +inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) { + GGLfixed result, t; + if (__builtin_constant_p(shift)) { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "add %[lo], %[a], %[lo], lsr %[rshift] \n" + "add %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x) + : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift) + ); + } else { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "add %[lo], %[a], %[lo], lsr %[rshift] \n" + "add %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x) + : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift) + ); + } + return result; +} + +inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST; +inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) { + GGLfixed result, t; + if (__builtin_constant_p(shift)) { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "rsb %[lo], %[a], %[lo], lsr %[rshift] \n" + "add %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x) + : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift) + ); + } else { + asm("smull %[lo], %[hi], %[x], %[y] \n" + "rsb %[lo], %[a], %[lo], lsr %[rshift] \n" + "add %[lo], %[lo], %[hi], lsl %[lshift] \n" + : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x) + : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift) + ); + } + return result; +} + +inline int64_t gglMulii(int32_t x, int32_t y) CONST; +inline int64_t gglMulii(int32_t x, int32_t y) +{ + // 64-bits result: r0=low, r1=high + union { + struct { + int32_t lo; + int32_t hi; + } s; + int64_t res; + }; + asm("smull %0, %1, %2, %3 \n" + : "=r"(s.lo), "=&r"(s.hi) + : "%r"(x), "r"(y) + : + ); + return res; +} + +#else // ---------------------------------------------------------------------- + +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST; +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) { + return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift); +} +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST; +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) { + return GGLfixed((int64_t(a)*b)>>shift) + c; +} +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST; +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) { + return GGLfixed((int64_t(a)*b)>>shift) - c; +} +inline int64_t gglMulii(int32_t a, int32_t b) CONST; +inline int64_t gglMulii(int32_t a, int32_t b) { + return int64_t(a)*b; +} + +#endif + +// ------------------------------------------------------------------------ + +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST; +inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) { + return gglMulx(a, b, 16); +} +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST; +inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) { + return gglMulAddx(a, b, c, 16); +} +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST; +inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) { + return gglMulSubx(a, b, c, 16); +} + +// ------------------------------------------------------------------------ + +inline int32_t gglClz(int32_t x) CONST; +inline int32_t gglClz(int32_t x) +{ +#if defined(__arm__) && !defined(__thumb__) + return __builtin_clz(x); +#else + if (!x) return 32; + int32_t exp = 31; + if (x & 0xFFFF0000) { exp -=16; x >>= 16; } + if (x & 0x0000ff00) { exp -= 8; x >>= 8; } + if (x & 0x000000f0) { exp -= 4; x >>= 4; } + if (x & 0x0000000c) { exp -= 2; x >>= 2; } + if (x & 0x00000002) { exp -= 1; } + return exp; +#endif +} + +// ------------------------------------------------------------------------ + +int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST; + +inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST; +inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) { + return gglDivQ(n, d, 16); +} + +inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST; +inline int32_t gglDivx(GGLfixed n, GGLfixed d) { + return gglDivQ(n, d, 16); +} + +// ------------------------------------------------------------------------ + +inline GGLfixed gglRecipFast(GGLfixed x) CONST; +inline GGLfixed gglRecipFast(GGLfixed x) +{ + // This is a really bad approximation of 1/x, but it's also + // very fast. x must be strictly positive. + // if x between [0.5, 1[ , then 1/x = 3-2*x + // (we use 2.30 fixed-point) + const int32_t lz = gglClz(x); + return (0xC0000000 - (x << (lz - 1))) >> (30-lz); +} + +// ------------------------------------------------------------------------ + +inline GGLfixed gglClampx(GGLfixed c) CONST; +inline GGLfixed gglClampx(GGLfixed c) +{ +#if defined(__thumb__) + // clamp without branches + c &= ~(c>>31); c = FIXED_ONE - c; + c &= ~(c>>31); c = FIXED_ONE - c; +#else +#if defined(__arm__) + // I don't know why gcc thinks its smarter than me! The code below + // clamps to zero in one instruction, but gcc won't generate it and + // replace it by a cmp + movlt (it's quite amazing actually). + asm("bic %0, %1, %1, asr #31\n" : "=r"(c) : "r"(c)); +#else + c &= ~(c>>31); +#endif + if (c>FIXED_ONE) + c = FIXED_ONE; +#endif + return c; +} + +// ------------------------------------------------------------------------ + +#endif // ANDROID_GGL_FIXED_H |